File indexing completed on 2024-05-12 04:57:53
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com> 0004 * 0005 * This program is free software: you can redistribute it and/or modify 0006 * it under the terms of the GNU General Public License as published by 0007 * the Free Software Foundation, either version 3 of the License, or 0008 * (at your option) any later version. 0009 * 0010 * This program is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 * GNU General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU General Public License 0016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0017 * ============================================================ */ 0018 #include "mainapplication.h" 0019 #include "history.h" 0020 #include "qztools.h" 0021 #include "updater.h" 0022 #include "autofill.h" 0023 #include "settings.h" 0024 #include "autosaver.h" 0025 #include "datapaths.h" 0026 #include "tabwidget.h" 0027 #include "cookiejar.h" 0028 #include "bookmarks.h" 0029 #include "qzsettings.h" 0030 #include "proxystyle.h" 0031 #include "pluginproxy.h" 0032 #include "iconprovider.h" 0033 #include "browserwindow.h" 0034 #include "checkboxdialog.h" 0035 #include "networkmanager.h" 0036 #include "profilemanager.h" 0037 #include "browsinglibrary.h" 0038 #include "downloadmanager.h" 0039 #include "clearprivatedata.h" 0040 #include "useragentmanager.h" 0041 #include "commandlineoptions.h" 0042 #include "searchenginesmanager.h" 0043 #include "desktopnotificationsfactory.h" 0044 #include "html5permissions/html5permissionsmanager.h" 0045 #include "scripts.h" 0046 #include "sessionmanager.h" 0047 #include "closedwindowsmanager.h" 0048 #include "protocolhandlermanager.h" 0049 #include "../config.h" 0050 0051 #include <QWebEngineSettings> 0052 #include <QDesktopServices> 0053 #include <QFontDatabase> 0054 #include <QSqlDatabase> 0055 #include <QLibraryInfo> 0056 #include <QMessageBox> 0057 #include <QTranslator> 0058 #include <QThreadPool> 0059 #include <QSettings> 0060 #include <QProcess> 0061 #include <QTimer> 0062 #include <QDir> 0063 #include <QStandardPaths> 0064 #include <QWebEngineProfile> 0065 #include <QWebEngineScriptCollection> 0066 #include <QRegularExpression> 0067 #include <QtWebEngineWidgetsVersion> 0068 #include <QtWebEngineCoreVersion> 0069 0070 #include <QWebEngineNotification> 0071 #include <QWebEngineUrlScheme> 0072 0073 #ifdef Q_OS_WIN 0074 #include <QtWin> 0075 #include <QWinJumpList> 0076 #include <QWinJumpListCategory> 0077 #endif 0078 0079 #include <iostream> 0080 0081 #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) 0082 #include "registerqappassociation.h" 0083 #endif 0084 0085 static bool s_testMode = false; 0086 0087 MainApplication::MainApplication(int &argc, char** argv) 0088 : QtSingleApplication(argc, argv) 0089 , m_isPrivate(false) 0090 , m_isPortable(false) 0091 , m_isClosing(false) 0092 , m_isStartingAfterCrash(false) 0093 , m_history(nullptr) 0094 , m_bookmarks(nullptr) 0095 , m_autoFill(nullptr) 0096 , m_cookieJar(nullptr) 0097 , m_plugins(nullptr) 0098 , m_browsingLibrary(nullptr) 0099 , m_networkManager(nullptr) 0100 , m_restoreManager(nullptr) 0101 , m_sessionManager(nullptr) 0102 , m_downloadManager(nullptr) 0103 , m_userAgentManager(nullptr) 0104 , m_searchEnginesManager(nullptr) 0105 , m_closedWindowsManager(nullptr) 0106 , m_protocolHandlerManager(nullptr) 0107 , m_html5PermissionsManager(nullptr) 0108 , m_desktopNotifications(nullptr) 0109 , m_webProfile(nullptr) 0110 , m_autoSaver(nullptr) 0111 #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) 0112 , m_registerQAppAssociation(0) 0113 #endif 0114 { 0115 setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); 0116 0117 setApplicationName(QStringLiteral("falkon")); 0118 setOrganizationDomain(QStringLiteral("org.kde")); 0119 setWindowIcon(QIcon::fromTheme(QSL("falkon"), QIcon(QSL(":icons/falkon.svg")))); 0120 setDesktopFileName(QSL("org.kde.falkon")); 0121 0122 #ifdef GIT_REVISION 0123 setApplicationVersion(QSL("%1 (%2)").arg(QString::fromLatin1(Qz::VERSION), GIT_REVISION)); 0124 #else 0125 setApplicationVersion(QString::fromLatin1(Qz::VERSION)); 0126 #endif 0127 0128 // Set fallback icon theme (eg. on Windows/Mac) 0129 if (QIcon::fromTheme(QSL("view-refresh")).isNull()) { 0130 QIcon::setThemeName(QSL("breeze-fallback")); 0131 } 0132 0133 // QSQLITE database plugin is required 0134 if (!QSqlDatabase::isDriverAvailable(QSL("QSQLITE"))) { 0135 QMessageBox::critical(nullptr, QSL("Error"), QSL("Qt SQLite database plugin is not available. Please install it and restart the application.")); 0136 m_isClosing = true; 0137 return; 0138 } 0139 0140 #ifdef Q_OS_WIN 0141 // Set default app font (needed for N'ko) 0142 int fontId = QFontDatabase::addApplicationFont(QSL("font.ttf")); 0143 if (fontId != -1) { 0144 const QStringList families = QFontDatabase::applicationFontFamilies(fontId); 0145 if (!families.empty()) 0146 setFont(QFont(families.at(0))); 0147 } 0148 #endif 0149 0150 QByteArray chromium_flags = qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"); 0151 chromium_flags.append(" --enable-features=WebRTCPipeWireCapturer"); 0152 qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromium_flags); 0153 0154 QUrl startUrl; 0155 QString startProfile; 0156 QStringList messages; 0157 0158 bool noAddons = false; 0159 bool newInstance = false; 0160 0161 if (argc > 1) { 0162 CommandLineOptions cmd; 0163 const auto actions = cmd.getActions(); 0164 for (const CommandLineOptions::ActionPair &pair : actions) { 0165 switch (pair.action) { 0166 case Qz::CL_StartWithoutAddons: 0167 noAddons = true; 0168 break; 0169 case Qz::CL_StartWithProfile: 0170 startProfile = pair.text; 0171 break; 0172 case Qz::CL_StartPortable: 0173 m_isPortable = true; 0174 break; 0175 case Qz::CL_NewTab: 0176 messages.append(QStringLiteral("ACTION:NewTab")); 0177 m_postLaunchActions.append(OpenNewTab); 0178 break; 0179 case Qz::CL_NewWindow: 0180 messages.append(QStringLiteral("ACTION:NewWindow")); 0181 break; 0182 case Qz::CL_ToggleFullScreen: 0183 messages.append(QStringLiteral("ACTION:ToggleFullScreen")); 0184 m_postLaunchActions.append(ToggleFullScreen); 0185 break; 0186 case Qz::CL_ShowDownloadManager: 0187 messages.append(QStringLiteral("ACTION:ShowDownloadManager")); 0188 m_postLaunchActions.append(OpenDownloadManager); 0189 break; 0190 case Qz::CL_StartPrivateBrowsing: 0191 m_isPrivate = true; 0192 break; 0193 case Qz::CL_StartNewInstance: 0194 newInstance = true; 0195 break; 0196 case Qz::CL_OpenUrlInCurrentTab: 0197 startUrl = QUrl::fromUserInput(pair.text); 0198 messages.append(QSL("ACTION:OpenUrlInCurrentTab") + pair.text); 0199 break; 0200 case Qz::CL_OpenUrlInNewWindow: 0201 startUrl = QUrl::fromUserInput(pair.text); 0202 messages.append(QSL("ACTION:OpenUrlInNewWindow") + pair.text); 0203 break; 0204 case Qz::CL_OpenUrl: 0205 startUrl = QUrl::fromUserInput(pair.text); 0206 messages.append(QSL("URL:") + pair.text); 0207 break; 0208 case Qz::CL_ExitAction: 0209 m_isClosing = true; 0210 return; 0211 case Qz::CL_WMClass: 0212 m_wmClass = pair.text.toUtf8(); 0213 break; 0214 default: 0215 break; 0216 } 0217 } 0218 } 0219 0220 if (!isPortable()) { 0221 QSettings falkonConf(QSL("%1/falkon.conf").arg(applicationDirPath()), QSettings::IniFormat); 0222 m_isPortable = falkonConf.value(QSL("Config/Portable")).toBool(); 0223 } 0224 0225 if (isPortable()) { 0226 std::cout << "Falkon: Running in Portable Mode." << std::endl; 0227 DataPaths::setPortableVersion(); 0228 } 0229 0230 // Don't start single application in private browsing 0231 if (!isPrivate()) { 0232 QString appId = QStringLiteral("org.kde.Falkon"); 0233 0234 if (isPortable()) { 0235 appId.append(QLatin1String(".Portable")); 0236 } 0237 0238 if (isTestModeEnabled()) { 0239 appId.append(QSL(".TestMode")); 0240 } 0241 0242 if (newInstance) { 0243 if (startProfile.isEmpty() || startProfile == QLatin1String("default")) { 0244 std::cout << "New instance cannot be started with default profile!" << std::endl; 0245 } 0246 else { 0247 // Generate unique appId so it is possible to start more separate instances 0248 // of the same profile. It is dangerous to run more instances of the same profile, 0249 // but if the user wants it, we should allow it. 0250 appId.append(QLatin1Char('.') + startProfile + QString::number(QDateTime::currentMSecsSinceEpoch())); 0251 } 0252 } 0253 0254 setAppId(appId); 0255 } 0256 0257 // If there is nothing to tell other instance, we need to at least wake it 0258 if (messages.isEmpty()) { 0259 messages.append(QStringLiteral(" ")); 0260 } 0261 0262 if (isRunning()) { 0263 m_isClosing = true; 0264 for (const QString &message : std::as_const(messages)) { 0265 sendMessage(message); 0266 } 0267 return; 0268 } 0269 0270 #ifdef Q_OS_MACOS 0271 setQuitOnLastWindowClosed(false); 0272 // disable tabbing issue#2261 0273 extern void disableWindowTabbing(); 0274 disableWindowTabbing(); 0275 #else 0276 setQuitOnLastWindowClosed(true); 0277 #endif 0278 0279 QSettings::setDefaultFormat(QSettings::IniFormat); 0280 QDesktopServices::setUrlHandler(QSL("http"), this, "addNewTab"); 0281 QDesktopServices::setUrlHandler(QSL("https"), this, "addNewTab"); 0282 QDesktopServices::setUrlHandler(QSL("ftp"), this, "addNewTab"); 0283 0284 ProfileManager profileManager; 0285 profileManager.initConfigDir(); 0286 profileManager.initCurrentProfile(startProfile); 0287 0288 Settings::createSettings(DataPaths::currentProfilePath() + QLatin1String("/settings.ini")); 0289 if (Settings::globalSettings()->value("Web-Browser-Settings/hardwareAccel", false).toBool()) { 0290 chromium_flags.append(" --enable-oop-rasterization --enable-gpu-rasterization --enable-native-gpu-memory-buffers --use-gl=desktop"); 0291 qputenv("QTWEBENGINE_CHROMIUM_FLAGS", chromium_flags); 0292 } 0293 0294 NetworkManager::registerSchemes(); 0295 registerAllowedSchemes(); 0296 0297 m_webProfile = isPrivate() ? new QWebEngineProfile() : new QWebEngineProfile(QSL("Default")); 0298 connect(m_webProfile, &QWebEngineProfile::downloadRequested, this, &MainApplication::downloadRequested); 0299 0300 m_webProfile->setNotificationPresenter([&] (std::unique_ptr<QWebEngineNotification> notification) { 0301 auto notifications = desktopNotifications(); 0302 notifications->showNotification( 0303 QPixmap::fromImage(notification->icon()), notification->title(), notification->message() 0304 ); 0305 }); 0306 0307 m_networkManager = new NetworkManager(this); 0308 0309 setupUserScripts(); 0310 0311 if (!isPrivate() && !isTestModeEnabled()) { 0312 m_sessionManager = new SessionManager(this); 0313 m_autoSaver = new AutoSaver(this); 0314 connect(m_autoSaver, &AutoSaver::save, m_sessionManager, &SessionManager::autoSaveLastSession); 0315 0316 Settings settings; 0317 settings.beginGroup(QSL("SessionRestore")); 0318 const bool wasRunning = settings.value(QSL("isRunning"), false).toBool(); 0319 const bool wasRestoring = settings.value(QSL("isRestoring"), false).toBool(); 0320 settings.setValue(QSL("isRunning"), true); 0321 settings.setValue(QSL("isRestoring"), wasRunning); 0322 settings.endGroup(); 0323 settings.sync(); 0324 0325 m_isStartingAfterCrash = wasRunning && wasRestoring; 0326 0327 if (wasRunning) { 0328 QTimer::singleShot(60 * 1000, this, [this]() { 0329 Settings().setValue(QSL("SessionRestore/isRestoring"), false); 0330 }); 0331 } 0332 0333 // we have to ask about startup session before creating main window 0334 if (!m_isStartingAfterCrash && afterLaunch() == SelectSession) 0335 m_restoreManager = new RestoreManager(sessionManager()->askSessionFromUser()); 0336 } 0337 0338 loadSettings(); 0339 0340 m_plugins = new PluginProxy(this); 0341 m_autoFill = new AutoFill(this); 0342 mApp->protocolHandlerManager(); 0343 0344 if (!noAddons) 0345 m_plugins->loadPlugins(); 0346 0347 BrowserWindow* window = createWindow(Qz::BW_FirstAppWindow, startUrl); 0348 connect(window, SIGNAL(startingCompleted()), this, SLOT(restoreOverrideCursor())); 0349 0350 connect(this, &QApplication::focusChanged, this, &MainApplication::onFocusChanged); 0351 0352 if (!isPrivate() && !isTestModeEnabled()) { 0353 #ifndef DISABLE_CHECK_UPDATES 0354 Settings settings; 0355 bool checkUpdates = settings.value("Web-Browser-Settings/CheckUpdates", true).toBool(); 0356 0357 if (checkUpdates) { 0358 new Updater(window); 0359 } 0360 #endif 0361 0362 sessionManager()->backupSavedSessions(); 0363 0364 if (m_isStartingAfterCrash || afterLaunch() == RestoreSession) { 0365 m_restoreManager = new RestoreManager(sessionManager()->lastActiveSessionPath()); 0366 if (!m_restoreManager->isValid()) { 0367 destroyRestoreManager(); 0368 } 0369 } 0370 0371 if (!m_isStartingAfterCrash && m_restoreManager) { 0372 restoreSession(window, m_restoreManager->restoreData()); 0373 } 0374 } 0375 0376 QSettings::setPath(QSettings::IniFormat, QSettings::UserScope, DataPaths::currentProfilePath()); 0377 0378 connect(this, SIGNAL(messageReceived(QString)), this, SLOT(messageReceived(QString))); 0379 connect(this, &QCoreApplication::aboutToQuit, this, &MainApplication::saveSettings); 0380 0381 QTimer::singleShot(0, this, &MainApplication::postLaunch); 0382 } 0383 0384 MainApplication::~MainApplication() 0385 { 0386 m_isClosing = true; 0387 0388 QDesktopServices::unsetUrlHandler(QSL("http")); 0389 QDesktopServices::unsetUrlHandler(QSL("https")); 0390 QDesktopServices::unsetUrlHandler(QSL("ftp")); 0391 0392 IconProvider::instance()->saveIconsToDatabase(); 0393 0394 // Wait for all QtConcurrent jobs to finish 0395 QThreadPool::globalInstance()->waitForDone(); 0396 0397 // Delete all classes that are saving data in destructor 0398 delete m_bookmarks; 0399 m_bookmarks = nullptr; 0400 delete m_cookieJar; 0401 m_cookieJar = nullptr; 0402 0403 // On Qt 6, deleting the web profile is necessary in order to make sure cache, cookies, etc. are flushed to disk. 0404 delete m_webProfile; 0405 m_webProfile = nullptr; 0406 0407 Settings::syncSettings(); 0408 } 0409 0410 bool MainApplication::isClosing() const 0411 { 0412 return m_isClosing; 0413 } 0414 0415 bool MainApplication::isPrivate() const 0416 { 0417 return m_isPrivate; 0418 } 0419 0420 bool MainApplication::isPortable() const 0421 { 0422 #ifdef PORTABLE_BUILD 0423 return true; 0424 #else 0425 return m_isPortable; 0426 #endif 0427 } 0428 0429 bool MainApplication::isStartingAfterCrash() const 0430 { 0431 return m_isStartingAfterCrash; 0432 } 0433 0434 int MainApplication::windowCount() const 0435 { 0436 return m_windows.count(); 0437 } 0438 0439 QList<BrowserWindow*> MainApplication::windows() const 0440 { 0441 return m_windows; 0442 } 0443 0444 BrowserWindow* MainApplication::getWindow() const 0445 { 0446 if (m_lastActiveWindow) { 0447 return m_lastActiveWindow.data(); 0448 } 0449 0450 return m_windows.isEmpty() ? nullptr : m_windows.at(0); 0451 } 0452 0453 BrowserWindow* MainApplication::createWindow(Qz::BrowserWindowType type, const QUrl &startUrl) 0454 { 0455 if (windowCount() == 0 && type != Qz::BW_MacFirstWindow) { 0456 type = Qz::BW_FirstAppWindow; 0457 } 0458 0459 auto* window = new BrowserWindow(type, startUrl); 0460 connect(window, &QObject::destroyed, this, &MainApplication::windowDestroyed); 0461 0462 m_windows.prepend(window); 0463 return window; 0464 } 0465 0466 MainApplication::AfterLaunch MainApplication::afterLaunch() const 0467 { 0468 return static_cast<AfterLaunch>(Settings().value(QSL("Web-URL-Settings/afterLaunch"), RestoreSession).toInt()); 0469 } 0470 0471 void MainApplication::openSession(BrowserWindow* window, RestoreData &restoreData) 0472 { 0473 setOverrideCursor(Qt::BusyCursor); 0474 0475 if (!window) 0476 window = createWindow(Qz::BW_OtherRestoredWindow); 0477 0478 if (window->tabCount() != 0) { 0479 // This can only happen when recovering crashed session! 0480 // Don't restore tabs in current window as user already opened some new tabs. 0481 createWindow(Qz::BW_OtherRestoredWindow)->restoreWindow(restoreData.windows.takeAt(0)); 0482 } else { 0483 window->restoreWindow(restoreData.windows.takeAt(0)); 0484 } 0485 0486 const auto restoreWindows = restoreData.windows; 0487 for (const BrowserWindow::SavedWindow &data : restoreWindows) { 0488 BrowserWindow* window = createWindow(Qz::BW_OtherRestoredWindow); 0489 window->restoreWindow(data); 0490 } 0491 0492 m_closedWindowsManager->restoreState(restoreData.closedWindows); 0493 0494 restoreOverrideCursor(); 0495 } 0496 0497 bool MainApplication::restoreSession(BrowserWindow* window, RestoreData restoreData) 0498 { 0499 if (m_isPrivate || !restoreData.isValid()) { 0500 return false; 0501 } 0502 0503 openSession(window, restoreData); 0504 0505 m_restoreManager->clearRestoreData(); 0506 destroyRestoreManager(); 0507 0508 return true; 0509 } 0510 0511 void MainApplication::destroyRestoreManager() 0512 { 0513 if (m_restoreManager && m_restoreManager->isValid()) { 0514 return; 0515 } 0516 0517 delete m_restoreManager; 0518 m_restoreManager = nullptr; 0519 } 0520 0521 void MainApplication::reloadSettings() 0522 { 0523 loadSettings(); 0524 Q_EMIT settingsReloaded(); 0525 } 0526 0527 QString MainApplication::styleName() const 0528 { 0529 return m_proxyStyle ? m_proxyStyle->name() : QString(); 0530 } 0531 0532 void MainApplication::setProxyStyle(ProxyStyle *style) 0533 { 0534 m_proxyStyle = style; 0535 setStyle(style); 0536 } 0537 0538 QByteArray MainApplication::wmClass() const 0539 { 0540 return m_wmClass; 0541 } 0542 0543 History* MainApplication::history() 0544 { 0545 if (!m_history) { 0546 m_history = new History(this); 0547 } 0548 return m_history; 0549 } 0550 0551 Bookmarks* MainApplication::bookmarks() 0552 { 0553 if (!m_bookmarks) { 0554 m_bookmarks = new Bookmarks(this); 0555 } 0556 return m_bookmarks; 0557 } 0558 0559 AutoFill* MainApplication::autoFill() 0560 { 0561 return m_autoFill; 0562 } 0563 0564 CookieJar* MainApplication::cookieJar() 0565 { 0566 if (!m_cookieJar) { 0567 m_cookieJar = new CookieJar(this); 0568 } 0569 return m_cookieJar; 0570 } 0571 0572 PluginProxy* MainApplication::plugins() 0573 { 0574 return m_plugins; 0575 } 0576 0577 BrowsingLibrary* MainApplication::browsingLibrary() 0578 { 0579 if (!m_browsingLibrary) { 0580 m_browsingLibrary = new BrowsingLibrary(getWindow()); 0581 } 0582 return m_browsingLibrary; 0583 } 0584 0585 NetworkManager *MainApplication::networkManager() 0586 { 0587 return m_networkManager; 0588 } 0589 0590 RestoreManager* MainApplication::restoreManager() 0591 { 0592 return m_restoreManager; 0593 } 0594 0595 SessionManager* MainApplication::sessionManager() 0596 { 0597 return m_sessionManager; 0598 } 0599 0600 DownloadManager* MainApplication::downloadManager() 0601 { 0602 if (!m_downloadManager) { 0603 m_downloadManager = new DownloadManager(); 0604 } 0605 return m_downloadManager; 0606 } 0607 0608 UserAgentManager* MainApplication::userAgentManager() 0609 { 0610 if (!m_userAgentManager) { 0611 m_userAgentManager = new UserAgentManager(this); 0612 } 0613 return m_userAgentManager; 0614 } 0615 0616 SearchEnginesManager* MainApplication::searchEnginesManager() 0617 { 0618 if (!m_searchEnginesManager) { 0619 m_searchEnginesManager = new SearchEnginesManager(this); 0620 } 0621 return m_searchEnginesManager; 0622 } 0623 0624 ClosedWindowsManager* MainApplication::closedWindowsManager() 0625 { 0626 if (!m_closedWindowsManager) { 0627 m_closedWindowsManager = new ClosedWindowsManager(this); 0628 } 0629 return m_closedWindowsManager; 0630 } 0631 0632 ProtocolHandlerManager *MainApplication::protocolHandlerManager() 0633 { 0634 if (!m_protocolHandlerManager) { 0635 m_protocolHandlerManager = new ProtocolHandlerManager(this); 0636 } 0637 return m_protocolHandlerManager; 0638 } 0639 0640 HTML5PermissionsManager* MainApplication::html5PermissionsManager() 0641 { 0642 if (!m_html5PermissionsManager) { 0643 m_html5PermissionsManager = new HTML5PermissionsManager(this); 0644 } 0645 return m_html5PermissionsManager; 0646 } 0647 0648 DesktopNotificationsFactory* MainApplication::desktopNotifications() 0649 { 0650 if (!m_desktopNotifications) { 0651 m_desktopNotifications = new DesktopNotificationsFactory(this); 0652 } 0653 return m_desktopNotifications; 0654 } 0655 0656 QWebEngineProfile *MainApplication::webProfile() const 0657 { 0658 return m_webProfile; 0659 } 0660 0661 QWebEngineSettings *MainApplication::webSettings() const 0662 { 0663 return m_webProfile->settings(); 0664 } 0665 0666 // static 0667 MainApplication* MainApplication::instance() 0668 { 0669 return static_cast<MainApplication*>(QCoreApplication::instance()); 0670 } 0671 0672 // static 0673 bool MainApplication::isTestModeEnabled() 0674 { 0675 return s_testMode; 0676 } 0677 0678 // static 0679 void MainApplication::setTestModeEnabled(bool enabled) 0680 { 0681 s_testMode = enabled; 0682 } 0683 0684 void MainApplication::addNewTab(const QUrl &url) 0685 { 0686 BrowserWindow* window = getWindow(); 0687 0688 if (window) { 0689 window->tabWidget()->addView(url, url.isEmpty() ? Qz::NT_SelectedNewEmptyTab : Qz::NT_SelectedTabAtTheEnd); 0690 } 0691 } 0692 0693 void MainApplication::startPrivateBrowsing(const QUrl &startUrl) 0694 { 0695 QUrl url = startUrl; 0696 if (auto* act = qobject_cast<QAction*>(sender())) { 0697 url = act->data().toUrl(); 0698 } 0699 0700 QStringList args; 0701 args.append(QSL("--private-browsing")); 0702 args.append(QSL("--profile=") + ProfileManager::currentProfile()); 0703 0704 if (!url.isEmpty()) { 0705 args << QString::fromUtf8(url.toEncoded()); 0706 } 0707 0708 if (!QProcess::startDetached(applicationFilePath(), args)) { 0709 qWarning() << "MainApplication: Cannot start new browser process for private browsing!" << applicationFilePath() << args; 0710 } 0711 } 0712 0713 void MainApplication::reloadUserStyleSheet() 0714 { 0715 const QString userCssFile = Settings().value(QSL("Web-Browser-Settings/userStyleSheet"), QString()).toString(); 0716 setUserStyleSheet(userCssFile); 0717 } 0718 0719 void MainApplication::restoreOverrideCursor() 0720 { 0721 QApplication::restoreOverrideCursor(); 0722 } 0723 0724 void MainApplication::changeOccurred() 0725 { 0726 if (m_autoSaver) 0727 m_autoSaver->changeOccurred(); 0728 } 0729 0730 void MainApplication::quitApplication() 0731 { 0732 if (m_downloadManager && !m_downloadManager->canClose()) { 0733 m_downloadManager->show(); 0734 return; 0735 } 0736 0737 for (BrowserWindow *window : std::as_const(m_windows)) { 0738 Q_EMIT window->aboutToClose(); 0739 } 0740 0741 if (m_sessionManager && m_windows.count() > 0) { 0742 m_sessionManager->autoSaveLastSession(); 0743 } 0744 0745 m_isClosing = true; 0746 0747 for (BrowserWindow *window : std::as_const(m_windows)) { 0748 window->close(); 0749 } 0750 0751 // Saving settings in saveSettings() slot called from quit() so 0752 // everything gets saved also when quitting application in other 0753 // way than clicking Quit action in File menu or closing last window 0754 // eg. on Mac (#157) 0755 0756 if (!isPrivate()) { 0757 removeLockFile(); 0758 } 0759 0760 quit(); 0761 } 0762 0763 void MainApplication::postLaunch() 0764 { 0765 if (m_postLaunchActions.contains(OpenDownloadManager)) { 0766 downloadManager()->show(); 0767 } 0768 0769 if (m_postLaunchActions.contains(OpenNewTab)) { 0770 getWindow()->tabWidget()->addView(QUrl(), Qz::NT_SelectedNewEmptyTab); 0771 } 0772 0773 if (m_postLaunchActions.contains(ToggleFullScreen)) { 0774 getWindow()->toggleFullScreen(); 0775 } 0776 0777 createJumpList(); 0778 initPulseSupport(); 0779 0780 QTimer::singleShot(5000, this, &MainApplication::runDeferredPostLaunchActions); 0781 } 0782 0783 QByteArray MainApplication::saveState() const 0784 { 0785 RestoreData restoreData; 0786 restoreData.windows.reserve(m_windows.count()); 0787 for (BrowserWindow *window : std::as_const(m_windows)) { 0788 restoreData.windows.append(BrowserWindow::SavedWindow(window)); 0789 } 0790 0791 if (m_restoreManager && m_restoreManager->isValid()) { 0792 QDataStream stream(&restoreData.crashedSession, QIODevice::WriteOnly); 0793 stream << m_restoreManager->restoreData(); 0794 } 0795 0796 restoreData.closedWindows = m_closedWindowsManager->saveState(); 0797 0798 QByteArray data; 0799 QDataStream stream(&data, QIODevice::WriteOnly); 0800 0801 stream << Qz::sessionVersion; 0802 stream << restoreData; 0803 0804 return data; 0805 } 0806 0807 void MainApplication::saveSettings() 0808 { 0809 if (isPrivate()) { 0810 return; 0811 } 0812 0813 m_isClosing = true; 0814 0815 Settings settings; 0816 settings.beginGroup(QSL("SessionRestore")); 0817 settings.setValue(QSL("isRunning"), false); 0818 settings.setValue(QSL("isRestoring"), false); 0819 settings.endGroup(); 0820 0821 settings.beginGroup(QSL("Web-Browser-Settings")); 0822 bool deleteCache = settings.value(QSL("deleteCacheOnClose"), false).toBool(); 0823 bool deleteHistory = settings.value(QSL("deleteHistoryOnClose"), false).toBool(); 0824 bool deleteHtml5Storage = settings.value(QSL("deleteHTML5StorageOnClose"), false).toBool(); 0825 settings.endGroup(); 0826 0827 settings.beginGroup(QSL("Cookie-Settings")); 0828 bool deleteCookies = settings.value(QSL("deleteCookiesOnClose"), false).toBool(); 0829 settings.endGroup(); 0830 0831 if (deleteHistory) { 0832 m_history->clearHistory(); 0833 } 0834 if (deleteHtml5Storage) { 0835 ClearPrivateData::clearLocalStorage(); 0836 } 0837 if (deleteCookies) { 0838 m_cookieJar->deleteAllCookies(false); 0839 } 0840 if (deleteCache) { 0841 QzTools::removeRecursively(mApp->webProfile()->cachePath()); 0842 } 0843 0844 m_searchEnginesManager->saveSettings(); 0845 m_plugins->shutdown(); 0846 m_networkManager->shutdown(); 0847 0848 qzSettings->saveSettings(); 0849 QFile::remove(DataPaths::currentProfilePath() + QLatin1String("/WebpageIcons.db")); 0850 0851 sessionManager()->saveSettings(); 0852 } 0853 0854 void MainApplication::messageReceived(const QString &message) 0855 { 0856 QWidget* actWin = getWindow(); 0857 QUrl actUrl; 0858 0859 if (message.startsWith(QLatin1String("URL:"))) { 0860 const QUrl url = QUrl::fromUserInput(message.mid(4)); 0861 addNewTab(url); 0862 actWin = getWindow(); 0863 } 0864 else if (message.startsWith(QLatin1String("ACTION:"))) { 0865 const QString text = message.mid(7); 0866 if (text == QLatin1String("NewTab")) { 0867 addNewTab(); 0868 } 0869 else if (text == QLatin1String("NewWindow")) { 0870 actWin = createWindow(Qz::BW_NewWindow); 0871 } 0872 else if (text == QLatin1String("ShowDownloadManager")) { 0873 downloadManager()->show(); 0874 actWin = downloadManager(); 0875 } 0876 else if (text == QLatin1String("ToggleFullScreen") && actWin) { 0877 auto* qz = static_cast<BrowserWindow*>(actWin); 0878 qz->toggleFullScreen(); 0879 } 0880 else if (text.startsWith(QLatin1String("OpenUrlInCurrentTab"))) { 0881 actUrl = QUrl::fromUserInput(text.mid(19)); 0882 } 0883 else if (text.startsWith(QLatin1String("OpenUrlInNewWindow"))) { 0884 createWindow(Qz::BW_NewWindow, QUrl::fromUserInput(text.mid(18))); 0885 return; 0886 } 0887 } 0888 else { 0889 // User attempted to start another instance, let's open a new window 0890 actWin = createWindow(Qz::BW_NewWindow); 0891 } 0892 0893 if (!actWin) { 0894 if (!isClosing()) { 0895 // It can only occur if download manager window was still opened 0896 createWindow(Qz::BW_NewWindow, actUrl); 0897 } 0898 return; 0899 } 0900 0901 actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized); 0902 actWin->raise(); 0903 actWin->activateWindow(); 0904 actWin->setFocus(); 0905 0906 auto* win = qobject_cast<BrowserWindow*>(actWin); 0907 0908 if (win && !actUrl.isEmpty()) { 0909 win->loadAddress(actUrl); 0910 } 0911 } 0912 0913 void MainApplication::windowDestroyed(QObject* window) 0914 { 0915 // qobject_cast doesn't work because QObject::destroyed is emitted from destructor 0916 Q_ASSERT(static_cast<BrowserWindow*>(window)); 0917 Q_ASSERT(m_windows.contains(static_cast<BrowserWindow*>(window))); 0918 0919 m_windows.removeOne(static_cast<BrowserWindow*>(window)); 0920 } 0921 0922 void MainApplication::onFocusChanged() 0923 { 0924 auto* activeBrowserWindow = qobject_cast<BrowserWindow*>(activeWindow()); 0925 0926 if (activeBrowserWindow) { 0927 m_lastActiveWindow = activeBrowserWindow; 0928 0929 Q_EMIT activeWindowChanged(m_lastActiveWindow); 0930 } 0931 } 0932 0933 void MainApplication::runDeferredPostLaunchActions() 0934 { 0935 checkDefaultWebBrowser(); 0936 checkOptimizeDatabase(); 0937 } 0938 0939 void MainApplication::downloadRequested(QWebEngineDownloadRequest *download) 0940 { 0941 downloadManager()->download(download); 0942 } 0943 0944 void MainApplication::loadSettings() 0945 { 0946 Settings settings; 0947 settings.beginGroup(QSL("Themes")); 0948 QString activeTheme = settings.value(QSL("activeTheme"), DEFAULT_THEME_NAME).toString(); 0949 settings.endGroup(); 0950 0951 loadTheme(activeTheme); 0952 0953 QWebEngineSettings* webSettings = m_webProfile->settings(); 0954 0955 // Web browsing settings 0956 settings.beginGroup(QSL("Web-Browser-Settings")); 0957 0958 webSettings->setAttribute(QWebEngineSettings::LocalStorageEnabled, settings.value(QSL("HTML5StorageEnabled"), true).toBool()); 0959 webSettings->setAttribute(QWebEngineSettings::PluginsEnabled, settings.value(QSL("allowPlugins"), true).toBool()); 0960 webSettings->setAttribute(QWebEngineSettings::JavascriptEnabled, settings.value(QSL("allowJavaScript"), true).toBool()); 0961 webSettings->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, settings.value(QSL("allowJavaScriptOpenWindow"), false).toBool()); 0962 webSettings->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, settings.value(QSL("allowJavaScriptAccessClipboard"), true).toBool()); 0963 webSettings->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, settings.value(QSL("IncludeLinkInFocusChain"), false).toBool()); 0964 webSettings->setAttribute(QWebEngineSettings::XSSAuditingEnabled, settings.value(QSL("XSSAuditing"), false).toBool()); 0965 webSettings->setAttribute(QWebEngineSettings::PrintElementBackgrounds, settings.value(QSL("PrintElementBackground"), true).toBool()); 0966 webSettings->setAttribute(QWebEngineSettings::SpatialNavigationEnabled, settings.value(QSL("SpatialNavigation"), false).toBool()); 0967 webSettings->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, settings.value(QSL("AnimateScrolling"), true).toBool()); 0968 webSettings->setAttribute(QWebEngineSettings::HyperlinkAuditingEnabled, false); 0969 webSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); 0970 webSettings->setAttribute(QWebEngineSettings::LocalContentCanAccessRemoteUrls, true); 0971 webSettings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); 0972 0973 webSettings->setAttribute(QWebEngineSettings::AllowWindowActivationFromJavaScript, settings.value(QSL("allowJavaScriptActivateWindow"), false).toBool()); 0974 0975 webSettings->setAttribute(QWebEngineSettings::JavascriptCanPaste, settings.value(QSL("allowJavaScriptPaste"), true).toBool()); 0976 webSettings->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, settings.value(QSL("DisableVideoAutoPlay"), false).toBool()); 0977 webSettings->setAttribute(QWebEngineSettings::WebRTCPublicInterfacesOnly, settings.value(QSL("WebRTCPublicIpOnly"), true).toBool()); 0978 webSettings->setUnknownUrlSchemePolicy(QWebEngineSettings::AllowAllUnknownUrlSchemes); 0979 webSettings->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, settings.value(QSL("DNSPrefetch"), true).toBool()); 0980 webSettings->setAttribute(QWebEngineSettings::PdfViewerEnabled, settings.value(QSL("intPDFViewer"), false).toBool()); 0981 webSettings->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, settings.value(QSL("screenCaptureEnabled"), false).toBool()); 0982 0983 webSettings->setDefaultTextEncoding(settings.value(QSL("DefaultEncoding"), webSettings->defaultTextEncoding()).toString()); 0984 0985 setWheelScrollLines(settings.value(QSL("wheelScrollLines"), wheelScrollLines()).toInt()); 0986 0987 const QString userCss = settings.value(QSL("userStyleSheet"), QString()).toString(); 0988 settings.endGroup(); 0989 0990 setUserStyleSheet(userCss); 0991 0992 settings.beginGroup(QSL("Browser-Fonts")); 0993 webSettings->setFontFamily(QWebEngineSettings::StandardFont, settings.value(QSL("StandardFont"), webSettings->fontFamily(QWebEngineSettings::StandardFont)).toString()); 0994 webSettings->setFontFamily(QWebEngineSettings::CursiveFont, settings.value(QSL("CursiveFont"), webSettings->fontFamily(QWebEngineSettings::CursiveFont)).toString()); 0995 webSettings->setFontFamily(QWebEngineSettings::FantasyFont, settings.value(QSL("FantasyFont"), webSettings->fontFamily(QWebEngineSettings::FantasyFont)).toString()); 0996 webSettings->setFontFamily(QWebEngineSettings::FixedFont, settings.value(QSL("FixedFont"), webSettings->fontFamily(QWebEngineSettings::FixedFont)).toString()); 0997 webSettings->setFontFamily(QWebEngineSettings::SansSerifFont, settings.value(QSL("SansSerifFont"), webSettings->fontFamily(QWebEngineSettings::SansSerifFont)).toString()); 0998 webSettings->setFontFamily(QWebEngineSettings::SerifFont, settings.value(QSL("SerifFont"), webSettings->fontFamily(QWebEngineSettings::SerifFont)).toString()); 0999 webSettings->setFontSize(QWebEngineSettings::DefaultFontSize, settings.value(QSL("DefaultFontSize"), 15).toInt()); 1000 webSettings->setFontSize(QWebEngineSettings::DefaultFixedFontSize, settings.value(QSL("FixedFontSize"), 14).toInt()); 1001 webSettings->setFontSize(QWebEngineSettings::MinimumFontSize, settings.value(QSL("MinimumFontSize"), 3).toInt()); 1002 webSettings->setFontSize(QWebEngineSettings::MinimumLogicalFontSize, settings.value(QSL("MinimumLogicalFontSize"), 5).toInt()); 1003 settings.endGroup(); 1004 1005 QWebEngineProfile* profile = m_webProfile; 1006 profile->setPersistentCookiesPolicy(QWebEngineProfile::AllowPersistentCookies); 1007 profile->setPersistentStoragePath(DataPaths::currentProfilePath()); 1008 1009 QString defaultPath = DataPaths::path(DataPaths::Cache); 1010 if (!defaultPath.startsWith(DataPaths::currentProfilePath())) 1011 defaultPath.append(QLatin1Char('/') + ProfileManager::currentProfile()); 1012 const QString &cachePath = settings.value(QSL("Web-Browser-Settings/CachePath"), defaultPath).toString(); 1013 profile->setCachePath(cachePath); 1014 1015 const bool allowCache = settings.value(QSL("Web-Browser-Settings/AllowLocalCache"), true).toBool(); 1016 profile->setHttpCacheType(allowCache ? QWebEngineProfile::DiskHttpCache : QWebEngineProfile::MemoryHttpCache); 1017 1018 const int cacheSize = settings.value(QSL("Web-Browser-Settings/LocalCacheSize"), 50).toInt() * 1000 * 1000; 1019 profile->setHttpCacheMaximumSize(cacheSize); 1020 1021 settings.beginGroup(QSL("SpellCheck")); 1022 profile->setSpellCheckEnabled(settings.value(QSL("Enabled"), false).toBool()); 1023 profile->setSpellCheckLanguages(settings.value(QSL("Languages")).toStringList()); 1024 settings.endGroup(); 1025 1026 if (isPrivate()) { 1027 profile->setPersistentStoragePath(DataPaths::path(DataPaths::Temp) + QLatin1String("/private-storage")); 1028 history()->setSaving(false); 1029 } 1030 1031 if (m_downloadManager) { 1032 m_downloadManager->loadSettings(); 1033 } 1034 1035 qzSettings->loadSettings(); 1036 userAgentManager()->loadSettings(); 1037 networkManager()->loadSettings(); 1038 } 1039 1040 void MainApplication::loadTheme(const QString &name) 1041 { 1042 QString activeThemePath = DataPaths::locate(DataPaths::Themes, name); 1043 1044 if (activeThemePath.isEmpty()) { 1045 qWarning() << "Cannot load theme " << name; 1046 activeThemePath = QSL("%1/%2").arg(DataPaths::path(DataPaths::Themes), DEFAULT_THEME_NAME); 1047 } 1048 1049 QString qss = QzTools::readAllFileContents(activeThemePath + QLatin1String("/main.css")); 1050 1051 #if defined(Q_OS_MACOS) 1052 qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/mac.css"))); 1053 #elif defined(Q_OS_UNIX) 1054 qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/linux.css"))); 1055 #elif defined(Q_OS_WIN) || defined(Q_OS_OS2) 1056 qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/windows.css"))); 1057 #endif 1058 1059 if (isRightToLeft()) { 1060 qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/rtl.css"))); 1061 } 1062 1063 if (isPrivate()) { 1064 qss.append(QzTools::readAllFileContents(activeThemePath + QLatin1String("/private.css"))); 1065 } 1066 1067 qss.append(QzTools::readAllFileContents(DataPaths::currentProfilePath() + QL1S("/userChrome.css"))); 1068 1069 QString relativePath = QDir::current().relativeFilePath(activeThemePath); 1070 qss.replace(QRegularExpression(QSL("url\\s*\\(\\s*([^\\*:\\);]+)\\s*\\)")), QSL("url(%1/\\1)").arg(relativePath)); 1071 setStyleSheet(qss); 1072 } 1073 1074 void MainApplication::checkDefaultWebBrowser() 1075 { 1076 if (isPortable()) { 1077 return; 1078 } 1079 1080 #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) 1081 Settings settings; 1082 bool checkNow = settings.value(QSL("Web-Browser-Settings/CheckDefaultBrowser"), DEFAULT_CHECK_DEFAULTBROWSER).toBool(); 1083 1084 if (!checkNow) { 1085 return; 1086 } 1087 1088 bool checkAgain = true; 1089 1090 if (!associationManager()->isDefaultForAllCapabilities()) { 1091 CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, getWindow()); 1092 dialog.setDefaultButton(QMessageBox::Yes); 1093 dialog.setText(tr("Falkon is not currently your default browser. Would you like to make it your default browser?")); 1094 dialog.setCheckBoxText(tr("Always perform this check when starting Falkon.")); 1095 dialog.setDefaultCheckState(Qt::Checked); 1096 dialog.setWindowTitle(tr("Default Browser")); 1097 dialog.setIcon(QMessageBox::Warning); 1098 1099 if (dialog.exec() == QMessageBox::Yes) { 1100 if (!mApp->associationManager()->showNativeDefaultAppSettingsUi()) 1101 mApp->associationManager()->registerAllAssociation(); 1102 } 1103 1104 checkAgain = dialog.isChecked(); 1105 } 1106 1107 settings.setValue(QSL("Web-Browser-Settings/CheckDefaultBrowser"), checkAgain); 1108 #endif 1109 } 1110 1111 void MainApplication::checkOptimizeDatabase() 1112 { 1113 Settings settings; 1114 settings.beginGroup(QSL("Browser")); 1115 const int numberOfRuns = settings.value(QSL("RunsWithoutOptimizeDb"), 0).toInt(); 1116 settings.setValue(QSL("RunsWithoutOptimizeDb"), numberOfRuns + 1); 1117 1118 if (numberOfRuns > 20) { 1119 std::cout << "Optimizing database..." << std::endl; 1120 IconProvider::instance()->clearOldIconsInDatabase(); 1121 settings.setValue(QSL("RunsWithoutOptimizeDb"), 0); 1122 } 1123 1124 settings.endGroup(); 1125 } 1126 1127 void MainApplication::registerAllowedSchemes() 1128 { 1129 for (const QString &schemeName : std::as_const(qzSettings->allowedSchemes)) { 1130 if (qzSettings->blockedSchemes.contains(schemeName)) { 1131 continue; 1132 } 1133 QWebEngineUrlScheme scheme(schemeName.toUtf8()); 1134 scheme.setFlags(QWebEngineUrlScheme::SecureScheme | QWebEngineUrlScheme::ContentSecurityPolicyIgnored); 1135 scheme.setSyntax(QWebEngineUrlScheme::Syntax::Path); 1136 QWebEngineUrlScheme::registerScheme(scheme); 1137 } 1138 } 1139 1140 void MainApplication::setupUserScripts() 1141 { 1142 // WebChannel for SafeJsWorld 1143 QWebEngineScript script; 1144 script.setName(QSL("_falkon_webchannel")); 1145 script.setInjectionPoint(QWebEngineScript::DocumentCreation); 1146 script.setWorldId(WebPage::SafeJsWorld); 1147 script.setRunsOnSubFrames(true); 1148 script.setSourceCode(Scripts::setupWebChannel()); 1149 m_webProfile->scripts()->insert(script); 1150 1151 // falkon:restore 1152 QWebEngineScript falkonRestore; 1153 falkonRestore.setWorldId(WebPage::SafeJsWorld); 1154 falkonRestore.setSourceCode(QzTools::readAllFileContents(QSL(":html/restore.user.js"))); 1155 m_webProfile->scripts()->insert(falkonRestore); 1156 1157 // falkon:speeddial 1158 QWebEngineScript falkonSpeedDial; 1159 falkonSpeedDial.setWorldId(WebPage::SafeJsWorld); 1160 falkonSpeedDial.setSourceCode(Scripts::setupSpeedDial()); 1161 m_webProfile->scripts()->insert(falkonSpeedDial); 1162 1163 // document.window object addons 1164 QWebEngineScript documentWindowAddons; 1165 documentWindowAddons.setName(QSL("_falkon_window_object")); 1166 documentWindowAddons.setInjectionPoint(QWebEngineScript::DocumentCreation); 1167 documentWindowAddons.setWorldId(WebPage::UnsafeJsWorld); 1168 documentWindowAddons.setRunsOnSubFrames(true); 1169 documentWindowAddons.setSourceCode(Scripts::setupWindowObject()); 1170 m_webProfile->scripts()->insert(documentWindowAddons); 1171 } 1172 1173 void MainApplication::setUserStyleSheet(const QString &filePath) 1174 { 1175 QString userCss; 1176 1177 #if !defined(Q_OS_UNIX) && !defined(Q_OS_MACOS) 1178 // Don't grey out selection on losing focus (to prevent graying out found text) 1179 QString highlightColor; 1180 QString highlightedTextColor; 1181 #ifdef Q_OS_MACOS 1182 highlightColor = QLatin1String("#b6d6fc"); 1183 highlightedTextColor = QLatin1String("#000"); 1184 #else 1185 QPalette pal = style()->standardPalette(); 1186 highlightColor = pal.color(QPalette::Highlight).name(); 1187 highlightedTextColor = pal.color(QPalette::HighlightedText).name(); 1188 #endif 1189 userCss += QString("::selection {background: %1; color: %2;} ").arg(highlightColor, highlightedTextColor); 1190 #endif 1191 1192 userCss += QzTools::readAllFileContents(filePath).remove(QLatin1Char('\n')); 1193 1194 const QString name = QStringLiteral("_falkon_userstylesheet"); 1195 for (const QWebEngineScript &oldScript : m_webProfile->scripts()->find(name)) { 1196 m_webProfile->scripts()->remove(oldScript); 1197 } 1198 1199 if (userCss.isEmpty()) 1200 return; 1201 1202 QWebEngineScript script; 1203 script.setName(name); 1204 script.setInjectionPoint(QWebEngineScript::DocumentReady); 1205 script.setWorldId(WebPage::SafeJsWorld); 1206 script.setRunsOnSubFrames(true); 1207 script.setSourceCode(Scripts::setCss(userCss)); 1208 m_webProfile->scripts()->insert(script); 1209 } 1210 1211 void MainApplication::createJumpList() 1212 { 1213 #ifdef Q_OS_WIN 1214 QWinJumpList *jumpList = new QWinJumpList(this); 1215 jumpList->clear(); 1216 1217 // Frequent 1218 QWinJumpListCategory *frequent = jumpList->frequent(); 1219 frequent->setVisible(true); 1220 const QVector<HistoryEntry> mostList = m_history->mostVisited(7); 1221 for (const HistoryEntry &entry : mostList) { 1222 frequent->addLink(IconProvider::iconForUrl(entry.url), entry.title, applicationFilePath(), QStringList{(QString::fromUtf8entry.url.toEncoded())}); 1223 } 1224 1225 // Tasks 1226 QWinJumpListCategory *tasks = jumpList->tasks(); 1227 tasks->setVisible(true); 1228 tasks->addLink(IconProvider::newTabIcon(), tr("Open new tab"), applicationFilePath(), {QSL("--new-tab")}); 1229 tasks->addLink(IconProvider::newWindowIcon(), tr("Open new window"), applicationFilePath(), {QSL("--new-window")}); 1230 tasks->addLink(IconProvider::privateBrowsingIcon(), tr("Open new private window"), applicationFilePath(), {QSL("--private-browsing")}); 1231 #endif 1232 } 1233 1234 void MainApplication::initPulseSupport() 1235 { 1236 qputenv("PULSE_PROP_OVERRIDE_application.name", "Falkon"); 1237 qputenv("PULSE_PROP_OVERRIDE_application.icon_name", "falkon"); 1238 qputenv("PULSE_PROP_OVERRIDE_media.icon_name", "falkon"); 1239 } 1240 1241 #if defined(Q_OS_WIN) && !defined(Q_OS_OS2) 1242 RegisterQAppAssociation* MainApplication::associationManager() 1243 { 1244 if (!m_registerQAppAssociation) { 1245 QString desc = tr("Falkon is a new and very fast Qt web browser. Falkon is licensed under GPL version 3 or (at your option) any later version. It is based on QtWebEngine and Qt Framework."); 1246 QString fileIconPath = QApplication::applicationFilePath() + QSL(",1"); 1247 QString appIconPath = QApplication::applicationFilePath() + QSL(",0"); 1248 m_registerQAppAssociation = new RegisterQAppAssociation(QSL("Falkon"), QApplication::applicationFilePath(), appIconPath, desc, this); 1249 m_registerQAppAssociation->addCapability(QSL(".html"), QSL("FalkonHTML"), QSL("Falkon HTML Document"), fileIconPath, RegisterQAppAssociation::FileAssociation); 1250 m_registerQAppAssociation->addCapability(QSL(".htm"), QSL("FalkonHTML"), QSL("Falkon HTML Document"), fileIconPath, RegisterQAppAssociation::FileAssociation); 1251 m_registerQAppAssociation->addCapability(QSL("http"), QSL("FalkonURL"), QSL("Falkon URL"), appIconPath, RegisterQAppAssociation::UrlAssociation); 1252 m_registerQAppAssociation->addCapability(QSL("https"), QSL("FalkonURL"), QSL("Falkon URL"), appIconPath, RegisterQAppAssociation::UrlAssociation); 1253 m_registerQAppAssociation->addCapability(QSL("ftp"), QSL("FalkonURL"), QSL("Falkon URL"), appIconPath, RegisterQAppAssociation::UrlAssociation); 1254 } 1255 return m_registerQAppAssociation; 1256 } 1257 #endif 1258 1259 #ifdef Q_OS_MACOS 1260 #include <QFileOpenEvent> 1261 1262 bool MainApplication::event(QEvent* e) 1263 { 1264 switch (e->type()) { 1265 case QEvent::FileOpen: { 1266 QFileOpenEvent *ev = static_cast<QFileOpenEvent*>(e); 1267 if (!ev->url().isEmpty()) { 1268 addNewTab(ev->url()); 1269 } else if (!ev->file().isEmpty()) { 1270 addNewTab(QUrl::fromLocalFile(ev->file())); 1271 } else { 1272 return false; 1273 } 1274 return true; 1275 } 1276 1277 case QEvent::ApplicationActivate: 1278 if (!activeWindow() && m_windows.isEmpty()) 1279 createWindow(Qz::BW_NewWindow); 1280 break; 1281 1282 default: 1283 break; 1284 } 1285 1286 return QtSingleApplication::event(e); 1287 } 1288 #endif