File indexing completed on 2024-05-12 04:57:52
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 "browserwindow.h" 0019 #include "tabwidget.h" 0020 #include "tabbar.h" 0021 #include "webpage.h" 0022 #include "tabbedwebview.h" 0023 #include "lineedit.h" 0024 #include "history.h" 0025 #include "locationbar.h" 0026 #include "websearchbar.h" 0027 #include "pluginproxy.h" 0028 #include "sidebar.h" 0029 #include "cookiejar.h" 0030 #include "cookiemanager.h" 0031 #include "bookmarkstoolbar.h" 0032 #include "clearprivatedata.h" 0033 #include "autofill.h" 0034 #include "mainapplication.h" 0035 #include "checkboxdialog.h" 0036 #include "clickablelabel.h" 0037 #include "docktitlebarwidget.h" 0038 #include "iconprovider.h" 0039 #include "progressbar.h" 0040 #include "closedwindowsmanager.h" 0041 #include "statusbar.h" 0042 #include "browsinglibrary.h" 0043 #include "navigationbar.h" 0044 #include "bookmarksimport/bookmarksimportdialog.h" 0045 #include "qztools.h" 0046 #include "reloadstopbutton.h" 0047 #include "enhancedmenu.h" 0048 #include "navigationcontainer.h" 0049 #include "settings.h" 0050 #include "qzsettings.h" 0051 #include "speeddial.h" 0052 #include "menubar.h" 0053 #include "bookmarkstools.h" 0054 #include "bookmarksmenu.h" 0055 #include "historymenu.h" 0056 #include "mainmenu.h" 0057 #include "downloadsbutton.h" 0058 #include "tabmodel.h" 0059 #include "tabmrumodel.h" 0060 0061 #include <algorithm> 0062 0063 #include <QKeyEvent> 0064 #include <QSplitter> 0065 #include <QMenuBar> 0066 #include <QTimer> 0067 #include <QShortcut> 0068 #include <QStackedWidget> 0069 #include <QTextCodec> 0070 #include <QFileDialog> 0071 #include <QDesktopServices> 0072 #include <QWebEngineHistory> 0073 #include <QWebEngineSettings> 0074 #include <QMessageBox> 0075 #include <QToolTip> 0076 #include <QScrollArea> 0077 #include <QCollator> 0078 #include <QTemporaryFile> 0079 #include <QActionGroup> 0080 0081 #ifdef QZ_WS_X11 0082 #include <xcb/xcb.h> 0083 #include <xcb/xcb_atom.h> 0084 #endif 0085 0086 static const int savedWindowVersion = 2; 0087 0088 BrowserWindow::SavedWindow::SavedWindow() 0089 = default; 0090 0091 BrowserWindow::SavedWindow::SavedWindow(BrowserWindow *window) 0092 { 0093 windowState = window->isFullScreen() ? QByteArray() : window->saveState(); 0094 windowGeometry = window->saveGeometry(); 0095 windowUiState = window->saveUiState(); 0096 #ifdef QZ_WS_X11 0097 virtualDesktop = window->getCurrentVirtualDesktop(); 0098 #endif 0099 0100 const int tabsCount = window->tabCount(); 0101 tabs.reserve(tabsCount); 0102 for (int i = 0; i < tabsCount; ++i) { 0103 TabbedWebView *webView = window->weView(i); 0104 if (!webView) { 0105 continue; 0106 } 0107 WebTab* webTab = webView->webTab(); 0108 if (!webTab) { 0109 continue; 0110 } 0111 WebTab::SavedTab tab(webTab); 0112 if (!tab.isValid()) { 0113 continue; 0114 } 0115 if (webTab->isCurrentTab()) { 0116 currentTab = tabs.size(); 0117 } 0118 tabs.append(tab); 0119 } 0120 } 0121 0122 bool BrowserWindow::SavedWindow::isValid() const 0123 { 0124 for (const WebTab::SavedTab &tab : std::as_const(tabs)) { 0125 if (!tab.isValid()) { 0126 return false; 0127 } 0128 } 0129 return currentTab > -1; 0130 } 0131 0132 void BrowserWindow::SavedWindow::clear() 0133 { 0134 windowState.clear(); 0135 windowGeometry.clear(); 0136 virtualDesktop = -1; 0137 currentTab = -1; 0138 tabs.clear(); 0139 } 0140 0141 QDataStream &operator<<(QDataStream &stream, const BrowserWindow::SavedWindow &window) 0142 { 0143 stream << savedWindowVersion; 0144 stream << window.windowState; 0145 stream << window.windowGeometry; 0146 stream << window.virtualDesktop; 0147 stream << window.currentTab; 0148 stream << static_cast<int>(window.tabs.count()); 0149 0150 for (int i = 0; i < window.tabs.count(); ++i) { 0151 stream << window.tabs.at(i); 0152 } 0153 0154 stream << window.windowUiState; 0155 0156 return stream; 0157 } 0158 0159 QDataStream &operator>>(QDataStream &stream, BrowserWindow::SavedWindow &window) 0160 { 0161 int version; 0162 stream >> version; 0163 0164 if (version < 1) { 0165 return stream; 0166 } 0167 0168 stream >> window.windowState; 0169 stream >> window.windowGeometry; 0170 stream >> window.virtualDesktop; 0171 stream >> window.currentTab; 0172 0173 int tabsCount = -1; 0174 stream >> tabsCount; 0175 window.tabs.reserve(tabsCount); 0176 0177 for (int i = 0; i < tabsCount; ++i) { 0178 WebTab::SavedTab tab; 0179 stream >> tab; 0180 window.tabs.append(tab); 0181 } 0182 0183 if (version >= 2) { 0184 stream >> window.windowUiState; 0185 } 0186 0187 return stream; 0188 } 0189 0190 BrowserWindow::BrowserWindow(Qz::BrowserWindowType type, const QUrl &startUrl) 0191 : QMainWindow(nullptr) 0192 , m_startUrl(startUrl) 0193 , m_windowType(type) 0194 , m_startTab(nullptr) 0195 , m_startPage(nullptr) 0196 , m_sideBarManager(new SideBarManager(this)) 0197 , m_hideNavigationTimer(nullptr) 0198 { 0199 setAttribute(Qt::WA_DeleteOnClose); 0200 setAttribute(Qt::WA_DontCreateNativeAncestors); 0201 0202 setObjectName(QSL("mainwindow")); 0203 setWindowTitle(tr("Falkon")); 0204 setProperty("private", mApp->isPrivate()); 0205 0206 setupUi(); 0207 setupMenu(); 0208 0209 m_hideNavigationTimer = new QTimer(this); 0210 m_hideNavigationTimer->setInterval(1000); 0211 m_hideNavigationTimer->setSingleShot(true); 0212 connect(m_hideNavigationTimer, &QTimer::timeout, this, &BrowserWindow::hideNavigationSlot); 0213 0214 connect(mApp, &MainApplication::settingsReloaded, this, &BrowserWindow::loadSettings); 0215 0216 QTimer::singleShot(0, this, &BrowserWindow::postLaunch); 0217 0218 if (mApp->isPrivate()) { 0219 QzTools::setWmClass(QSL("Falkon Browser (Private Window)"), this); 0220 } 0221 else { 0222 QzTools::setWmClass(QSL("Falkon Browser"), this); 0223 } 0224 } 0225 0226 BrowserWindow::~BrowserWindow() 0227 { 0228 mApp->plugins()->emitMainWindowDeleted(this); 0229 0230 for (const QPointer<QWidget> &pointer : std::as_const(m_deleteOnCloseWidgets)) { 0231 if (pointer) { 0232 pointer->deleteLater(); 0233 } 0234 } 0235 } 0236 0237 void BrowserWindow::setStartTab(WebTab* tab) 0238 { 0239 m_startTab = tab; 0240 } 0241 0242 void BrowserWindow::setStartPage(WebPage *page) 0243 { 0244 m_startPage = page; 0245 } 0246 0247 void BrowserWindow::postLaunch() 0248 { 0249 loadSettings(); 0250 0251 bool addTab = true; 0252 QUrl startUrl; 0253 0254 switch (mApp->afterLaunch()) { 0255 case MainApplication::OpenBlankPage: 0256 startUrl = QUrl(); 0257 break; 0258 0259 case MainApplication::OpenSpeedDial: 0260 startUrl = QUrl(QSL("falkon:speeddial")); 0261 break; 0262 0263 case MainApplication::OpenHomePage: 0264 case MainApplication::RestoreSession: 0265 case MainApplication::SelectSession: 0266 startUrl = m_homepage; 0267 break; 0268 0269 default: 0270 break; 0271 } 0272 0273 if (!mApp->isTestModeEnabled()) { 0274 show(); 0275 } 0276 0277 switch (m_windowType) { 0278 case Qz::BW_FirstAppWindow: 0279 if (mApp->isStartingAfterCrash()) { 0280 addTab = false; 0281 startUrl.clear(); 0282 m_tabWidget->addView(QUrl(QSL("falkon:restore")), Qz::NT_CleanSelectedTabAtTheEnd); 0283 } 0284 else if (mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) { 0285 addTab = m_tabWidget->count() <= 0; 0286 } 0287 break; 0288 0289 case Qz::BW_NewWindow: 0290 case Qz::BW_MacFirstWindow: 0291 addTab = true; 0292 break; 0293 0294 case Qz::BW_OtherRestoredWindow: 0295 addTab = false; 0296 break; 0297 } 0298 0299 if (!m_startUrl.isEmpty()) { 0300 startUrl = m_startUrl; 0301 addTab = true; 0302 } 0303 0304 if (m_startTab) { 0305 addTab = false; 0306 m_tabWidget->addView(m_startTab, Qz::NT_SelectedTab); 0307 } 0308 0309 if (m_startPage) { 0310 addTab = false; 0311 m_tabWidget->addView(QUrl()); 0312 weView()->setPage(m_startPage); 0313 } 0314 0315 if (addTab) { 0316 m_tabWidget->addView(startUrl, Qz::NT_CleanSelectedTabAtTheEnd); 0317 0318 if (startUrl.isEmpty() || startUrl.toString() == QLatin1String("falkon:speeddial")) { 0319 locationBar()->setFocus(); 0320 } 0321 } 0322 0323 // Something went really wrong .. add one tab 0324 if (m_tabWidget->count() <= 0) { 0325 m_tabWidget->addView(m_homepage, Qz::NT_SelectedTabAtTheEnd); 0326 } 0327 0328 mApp->plugins()->emitMainWindowCreated(this); 0329 Q_EMIT startingCompleted(); 0330 0331 raise(); 0332 activateWindow(); 0333 updateStartupFocus(); 0334 } 0335 0336 void BrowserWindow::setupUi() 0337 { 0338 Settings settings; 0339 settings.beginGroup(QSL("Browser-View-Settings")); 0340 const QByteArray windowGeometry = settings.value(QSL("WindowGeometry")).toByteArray(); 0341 0342 const QStringList keys = { 0343 QSL("LocationBarWidth"), 0344 QSL("WebSearchBarWidth"), 0345 QSL("SideBarWidth"), 0346 QSL("WebViewWidth"), 0347 QSL("SideBar") 0348 }; 0349 QHash<QString, QVariant> uiState; 0350 for (const QString &key : keys) { 0351 if (settings.contains(key)) { 0352 uiState[key] = settings.value(key); 0353 } 0354 } 0355 settings.endGroup(); 0356 0357 auto* widget = new QWidget(this); 0358 widget->setCursor(Qt::ArrowCursor); 0359 setCentralWidget(widget); 0360 0361 m_mainLayout = new QVBoxLayout(widget); 0362 m_mainLayout->setContentsMargins(0, 0, 0, 0); 0363 m_mainLayout->setSpacing(0); 0364 m_mainSplitter = new QSplitter(this); 0365 m_mainSplitter->setObjectName(QSL("sidebar-splitter")); 0366 m_tabWidget = new TabWidget(this); 0367 m_superMenu = new QMenu(this); 0368 m_navigationToolbar = new NavigationBar(this); 0369 m_bookmarksToolbar = new BookmarksToolbar(this); 0370 0371 m_tabModel = new TabModel(this, this); 0372 m_tabMruModel = new TabMruModel(this, this); 0373 m_tabMruModel->setSourceModel(m_tabModel); 0374 0375 m_navigationContainer = new NavigationContainer(this); 0376 m_navigationContainer->addWidget(m_navigationToolbar); 0377 m_navigationContainer->addWidget(m_bookmarksToolbar); 0378 m_navigationContainer->setTabBar(m_tabWidget->tabBar()); 0379 0380 m_mainSplitter->addWidget(m_tabWidget); 0381 m_mainSplitter->setCollapsible(0, false); 0382 0383 m_mainLayout->addWidget(m_navigationContainer); 0384 m_mainLayout->addWidget(m_mainSplitter); 0385 0386 m_statusBar = new StatusBar(this); 0387 m_statusBar->setObjectName(QSL("mainwindow-statusbar")); 0388 m_statusBar->setCursor(Qt::ArrowCursor); 0389 setStatusBar(m_statusBar); 0390 m_progressBar = new ProgressBar(m_statusBar); 0391 m_ipLabel = new QLabel(this); 0392 m_ipLabel->setObjectName(QSL("statusbar-ip-label")); 0393 m_ipLabel->setToolTip(tr("IP Address of current page")); 0394 0395 m_statusBar->addPermanentWidget(m_progressBar); 0396 m_statusBar->addPermanentWidget(m_ipLabel); 0397 0398 auto *downloadsButton = new DownloadsButton(this); 0399 m_statusBar->addButton(downloadsButton); 0400 m_navigationToolbar->addToolButton(downloadsButton); 0401 0402 auto desktop = QGuiApplication::primaryScreen(); 0403 int windowWidth = desktop->availableGeometry().width() / 1.3; 0404 int windowHeight = desktop->availableGeometry().height() / 1.3; 0405 0406 // Let the WM decides where to put new browser window 0407 if (m_windowType != Qz::BW_FirstAppWindow && m_windowType != Qz::BW_MacFirstWindow && mApp->getWindow()) { 0408 #ifdef Q_WS_WIN 0409 // Windows WM places every new window in the middle of screen .. for some reason 0410 QPoint p = mApp->getWindow()->geometry().topLeft(); 0411 p.setX(p.x() + 30); 0412 p.setY(p.y() + 30); 0413 0414 if (!desktop->availableGeometry(mApp->getWindow()).contains(p)) { 0415 p.setX(desktop->availableGeometry(mApp->getWindow()).x() + 30); 0416 p.setY(desktop->availableGeometry(mApp->getWindow()).y() + 30); 0417 } 0418 0419 setGeometry(QRect(p, mApp->getWindow()->size())); 0420 #else 0421 resize(mApp->getWindow()->size()); 0422 #endif 0423 } else if (!restoreGeometry(windowGeometry)) { 0424 #ifdef Q_WS_WIN 0425 setGeometry(QRect(desktop->availableGeometry(mApp->getWindow()).x() + 30, 0426 desktop->availableGeometry(mApp->getWindow()).y() + 30, windowWidth, windowHeight)); 0427 #else 0428 resize(windowWidth, windowHeight); 0429 #endif 0430 } 0431 0432 restoreUiState(uiState); 0433 0434 // Set some sane minimum width 0435 setMinimumWidth(300); 0436 } 0437 0438 void BrowserWindow::setupMenu() 0439 { 0440 #ifdef Q_OS_MACOS 0441 static MainMenu* macMainMenu = 0; 0442 0443 if (!macMainMenu) { 0444 macMainMenu = new MainMenu(this, 0); 0445 macMainMenu->initMenuBar(new QMenuBar(0)); 0446 connect(mApp, SIGNAL(activeWindowChanged(BrowserWindow*)), macMainMenu, SLOT(setWindow(BrowserWindow*))); 0447 } 0448 else { 0449 macMainMenu->setWindow(this); 0450 } 0451 0452 m_mainMenu = macMainMenu; 0453 #else 0454 setMenuBar(new MenuBar(this)); 0455 0456 m_mainMenu = new MainMenu(this, this); 0457 m_mainMenu->initMenuBar(menuBar()); 0458 #endif 0459 m_mainMenu->initSuperMenu(m_superMenu); 0460 0461 // Setup other shortcuts 0462 auto* reloadBypassCacheAction = new QShortcut(QKeySequence(QSL("Ctrl+F5")), this); 0463 auto* reloadBypassCacheAction2 = new QShortcut(QKeySequence(QSL("Ctrl+Shift+R")), this); 0464 connect(reloadBypassCacheAction, &QShortcut::activated, this, &BrowserWindow::reloadBypassCache); 0465 connect(reloadBypassCacheAction2, &QShortcut::activated, this, &BrowserWindow::reloadBypassCache); 0466 0467 auto* closeTabAction = new QShortcut(QKeySequence(QSL("Ctrl+W")), this); 0468 auto* closeTabAction2 = new QShortcut(QKeySequence(QSL("Ctrl+F4")), this); 0469 connect(closeTabAction, &QShortcut::activated, this, &BrowserWindow::closeTab); 0470 connect(closeTabAction2, &QShortcut::activated, this, &BrowserWindow::closeTab); 0471 0472 auto* reloadAction = new QShortcut(QKeySequence(QSL("Ctrl+R")), this); 0473 connect(reloadAction, &QShortcut::activated, this, &BrowserWindow::reload); 0474 0475 auto* openLocationAction = new QShortcut(QKeySequence(QSL("Alt+D")), this); 0476 connect(openLocationAction, &QShortcut::activated, this, &BrowserWindow::openLocation); 0477 0478 auto* inspectorAction = new QShortcut(QKeySequence(QSL("F12")), this); 0479 connect(inspectorAction, &QShortcut::activated, this, &BrowserWindow::toggleWebInspector); 0480 0481 auto* restoreClosedWindow = new QShortcut(QKeySequence(QSL("Ctrl+Shift+N")), this); 0482 connect(restoreClosedWindow, &QShortcut::activated, mApp->closedWindowsManager(), &ClosedWindowsManager::restoreClosedWindow); 0483 } 0484 0485 void BrowserWindow::updateStartupFocus() 0486 { 0487 QTimer::singleShot(500, this, [this]() { 0488 // Scroll to current tab 0489 tabWidget()->tabBar()->ensureVisible(); 0490 // Update focus 0491 if (!m_startPage && LocationBar::convertUrlToText(weView()->page()->requestedUrl()).isEmpty()) 0492 locationBar()->setFocus(); 0493 else 0494 weView()->setFocus(); 0495 }); 0496 } 0497 0498 QAction* BrowserWindow::createEncodingAction(const QString &codecName, 0499 const QString &activeCodecName, QMenu* menu) 0500 { 0501 auto* action = new QAction(codecName, menu); 0502 action->setData(codecName); 0503 action->setCheckable(true); 0504 connect(action, &QAction::triggered, this, &BrowserWindow::changeEncoding); 0505 if (activeCodecName.compare(codecName, Qt::CaseInsensitive) == 0) { 0506 action->setChecked(true); 0507 } 0508 return action; 0509 } 0510 0511 void BrowserWindow::createEncodingSubMenu(const QString &name, QStringList &codecNames, QMenu* menu) 0512 { 0513 if (codecNames.isEmpty()) { 0514 return; 0515 } 0516 0517 QCollator collator; 0518 collator.setNumericMode(true); 0519 std::sort(codecNames.begin(), codecNames.end(), [collator](const QString &a, const QString &b) { 0520 return collator.compare(a, b) < 0; 0521 }); 0522 0523 auto* subMenu = new QMenu(name, menu); 0524 const QString activeCodecName = mApp->webSettings()->defaultTextEncoding(); 0525 0526 auto *group = new QActionGroup(subMenu); 0527 0528 for (const QString &codecName : std::as_const(codecNames)) { 0529 QAction *act = createEncodingAction(codecName, activeCodecName, subMenu); 0530 group->addAction(act); 0531 subMenu->addAction(act); 0532 } 0533 0534 menu->addMenu(subMenu); 0535 } 0536 0537 QHash<QString, QVariant> BrowserWindow::saveUiState() 0538 { 0539 saveSideBarSettings(); 0540 0541 QHash<QString, QVariant> state; 0542 state[QSL("LocationBarWidth")] = m_navigationToolbar->splitter()->sizes().at(0); 0543 state[QSL("WebSearchBarWidth")] = m_navigationToolbar->splitter()->sizes().at(1); 0544 state[QSL("SideBarWidth")] = m_sideBarWidth; 0545 state[QSL("WebViewWidth")] = m_webViewWidth; 0546 state[QSL("SideBar")] = m_sideBarManager->activeSideBar(); 0547 return state; 0548 } 0549 0550 void BrowserWindow::restoreUiState(const QHash<QString, QVariant> &state) 0551 { 0552 const int locationBarWidth = state.value(QSL("LocationBarWidth"), 480).toInt(); 0553 const int websearchBarWidth = state.value(QSL("WebSearchBarWidth"), 140).toInt(); 0554 m_navigationToolbar->setSplitterSizes(locationBarWidth, websearchBarWidth); 0555 0556 m_sideBarWidth = state.value(QSL("SideBarWidth"), 250).toInt(); 0557 m_webViewWidth = state.value(QSL("WebViewWidth"), 2000).toInt(); 0558 if (m_sideBar) { 0559 m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth}); 0560 } 0561 0562 const QString activeSideBar = state.value(QSL("SideBar")).toString(); 0563 if (activeSideBar.isEmpty() && m_sideBar) { 0564 m_sideBar->close(); 0565 } else { 0566 m_sideBarManager->showSideBar(activeSideBar, false); 0567 } 0568 } 0569 0570 void BrowserWindow::loadSettings() 0571 { 0572 Settings settings; 0573 0574 //Url settings 0575 settings.beginGroup(QSL("Web-URL-Settings")); 0576 m_homepage = settings.value(QSL("homepage"), QSL("falkon:start")).toUrl(); 0577 settings.endGroup(); 0578 0579 //Browser Window settings 0580 settings.beginGroup(QSL("Browser-View-Settings")); 0581 bool showStatusBar = settings.value(QSL("showStatusBar"), false).toBool(); 0582 bool showBookmarksToolbar = settings.value(QSL("showBookmarksToolbar"), false).toBool(); 0583 bool showNavigationToolbar = settings.value(QSL("showNavigationToolbar"), true).toBool(); 0584 bool showMenuBar = settings.value(QSL("showMenubar"), false).toBool(); 0585 0586 // Make sure both menubar and navigationbar are not hidden 0587 // Fixes #781 0588 if (!showNavigationToolbar) { 0589 showMenuBar = true; 0590 settings.setValue(QSL("showMenubar"), true); 0591 } 0592 0593 settings.endGroup(); 0594 0595 settings.beginGroup(QSL("Shortcuts")); 0596 m_useTabNumberShortcuts = settings.value(QSL("useTabNumberShortcuts"), true).toBool(); 0597 m_useSpeedDialNumberShortcuts = settings.value(QSL("useSpeedDialNumberShortcuts"), true).toBool(); 0598 m_useSingleKeyShortcuts = settings.value(QSL("useSingleKeyShortcuts"), false).toBool(); 0599 settings.endGroup(); 0600 0601 settings.beginGroup(QSL("Web-Browser-Settings")); 0602 QAction *quitAction = m_mainMenu->action(QSL("Standard/Quit")); 0603 if (settings.value(QSL("closeAppWithCtrlQ"), true).toBool()) { 0604 quitAction->setShortcut(QzTools::actionShortcut(QKeySequence::Quit, QKeySequence(QSL("Ctrl+Q")))); 0605 } else { 0606 quitAction->setShortcut(QKeySequence()); 0607 } 0608 settings.endGroup(); 0609 0610 m_statusBarVisible = showStatusBar; 0611 statusBar()->setVisible(!isFullScreen() && showStatusBar); 0612 m_bookmarksToolbar->setVisible(showBookmarksToolbar); 0613 m_navigationToolbar->setVisible(showNavigationToolbar); 0614 0615 #ifndef Q_OS_MACOS 0616 m_menuBarVisible = showMenuBar; 0617 menuBar()->setVisible(!isFullScreen() && showMenuBar); 0618 #endif 0619 0620 m_navigationToolbar->setSuperMenuVisible(isFullScreen() || !showMenuBar); 0621 } 0622 0623 void BrowserWindow::goForward() 0624 { 0625 weView()->forward(); 0626 } 0627 0628 void BrowserWindow::reload() 0629 { 0630 weView()->reload(); 0631 } 0632 0633 void BrowserWindow::reloadBypassCache() 0634 { 0635 weView()->reloadBypassCache(); 0636 } 0637 0638 void BrowserWindow::goBack() 0639 { 0640 weView()->back(); 0641 } 0642 0643 int BrowserWindow::tabCount() const 0644 { 0645 return m_tabWidget->count(); 0646 } 0647 0648 TabbedWebView* BrowserWindow::weView() const 0649 { 0650 return weView(m_tabWidget->currentIndex()); 0651 } 0652 0653 TabbedWebView* BrowserWindow::weView(int index) const 0654 { 0655 auto* webTab = qobject_cast<WebTab*>(m_tabWidget->widget(index)); 0656 if (!webTab) { 0657 return nullptr; 0658 } 0659 0660 return webTab->webView(); 0661 } 0662 0663 LocationBar* BrowserWindow::locationBar() const 0664 { 0665 return qobject_cast<LocationBar*>(m_tabWidget->locationBars()->currentWidget()); 0666 } 0667 0668 TabWidget* BrowserWindow::tabWidget() const 0669 { 0670 return m_tabWidget; 0671 } 0672 0673 BookmarksToolbar* BrowserWindow::bookmarksToolbar() const 0674 { 0675 return m_bookmarksToolbar; 0676 } 0677 0678 StatusBar* BrowserWindow::statusBar() const 0679 { 0680 return m_statusBar; 0681 } 0682 0683 NavigationBar* BrowserWindow::navigationBar() const 0684 { 0685 return m_navigationToolbar; 0686 } 0687 0688 SideBarManager* BrowserWindow::sideBarManager() const 0689 { 0690 return m_sideBarManager; 0691 } 0692 0693 QLabel* BrowserWindow::ipLabel() const 0694 { 0695 return m_ipLabel; 0696 } 0697 0698 QMenu* BrowserWindow::superMenu() const 0699 { 0700 return m_superMenu; 0701 } 0702 0703 QUrl BrowserWindow::homepageUrl() const 0704 { 0705 return m_homepage; 0706 } 0707 0708 Qz::BrowserWindowType BrowserWindow::windowType() const 0709 { 0710 return m_windowType; 0711 } 0712 0713 QAction* BrowserWindow::action(const QString &name) const 0714 { 0715 return m_mainMenu->action(name); 0716 } 0717 0718 TabModel *BrowserWindow::tabModel() const 0719 { 0720 return m_tabModel; 0721 } 0722 0723 TabMruModel *BrowserWindow::tabMruModel() const 0724 { 0725 return m_tabMruModel; 0726 } 0727 0728 void BrowserWindow::setWindowTitle(const QString &t) 0729 { 0730 QString title = t; 0731 0732 if (mApp->isPrivate()) { 0733 title.append(tr(" (Private Browsing)")); 0734 } 0735 0736 QMainWindow::setWindowTitle(title); 0737 } 0738 0739 void BrowserWindow::changeEncoding() 0740 { 0741 if (auto* action = qobject_cast<QAction*>(sender())) { 0742 const QString encoding = action->data().toString(); 0743 mApp->webSettings()->setDefaultTextEncoding(encoding); 0744 0745 Settings settings; 0746 settings.setValue(QSL("Web-Browser-Settings/DefaultEncoding"), encoding); 0747 0748 weView()->reload(); 0749 } 0750 } 0751 0752 void BrowserWindow::printPage() 0753 { 0754 weView()->printPage(); 0755 } 0756 0757 void BrowserWindow::bookmarkPage() 0758 { 0759 TabbedWebView* view = weView(); 0760 BookmarksTools::addBookmarkDialog(this, view->url(), view->title()); 0761 } 0762 0763 void BrowserWindow::bookmarkAllTabs() 0764 { 0765 BookmarksTools::bookmarkAllTabsDialog(this, m_tabWidget); 0766 } 0767 0768 void BrowserWindow::addBookmark(const QUrl &url, const QString &title) 0769 { 0770 BookmarksTools::addBookmarkDialog(this, url, title); 0771 } 0772 0773 void BrowserWindow::goHome() 0774 { 0775 loadAddress(m_homepage); 0776 } 0777 0778 void BrowserWindow::goHomeInNewTab() 0779 { 0780 m_tabWidget->addView(m_homepage, Qz::NT_SelectedTab); 0781 } 0782 0783 void BrowserWindow::loadActionUrl(QObject* obj) 0784 { 0785 if (!obj) { 0786 obj = sender(); 0787 } 0788 0789 if (auto* action = qobject_cast<QAction*>(obj)) { 0790 loadAddress(action->data().toUrl()); 0791 } 0792 } 0793 0794 void BrowserWindow::loadActionUrlInNewTab(QObject* obj) 0795 { 0796 if (!obj) { 0797 obj = sender(); 0798 } 0799 0800 if (auto* action = qobject_cast<QAction*>(obj)) { 0801 m_tabWidget->addView(action->data().toUrl(), Qz::NT_SelectedTabAtTheEnd); 0802 } 0803 } 0804 0805 void BrowserWindow::loadAddress(const QUrl &url) 0806 { 0807 if (weView()->webTab()->isPinned()) { 0808 int index = m_tabWidget->addView(url, qzSettings->newTabPosition); 0809 weView(index)->setFocus(); 0810 } else { 0811 weView()->setFocus(); 0812 weView()->load(LoadRequest(url)); 0813 } 0814 } 0815 0816 void BrowserWindow::showHistoryManager() 0817 { 0818 mApp->browsingLibrary()->showHistory(this); 0819 } 0820 0821 void BrowserWindow::showSource(WebView *view) 0822 { 0823 if (!view) 0824 view = weView(); 0825 view->showSource(); 0826 } 0827 0828 SideBar* BrowserWindow::addSideBar() 0829 { 0830 if (m_sideBar) { 0831 return m_sideBar.data(); 0832 } 0833 0834 m_sideBar = new SideBar(m_sideBarManager, this); 0835 0836 m_mainSplitter->insertWidget(0, m_sideBar.data()); 0837 m_mainSplitter->setCollapsible(0, false); 0838 m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth}); 0839 0840 return m_sideBar.data(); 0841 } 0842 0843 void BrowserWindow::saveSideBarSettings() 0844 { 0845 if (m_sideBar) { 0846 // That +1 is important here, without it, the sidebar width would 0847 // decrease by 1 pixel every close 0848 m_sideBarWidth = m_mainSplitter->sizes().at(0) + 1; 0849 m_webViewWidth = width() - m_sideBarWidth; 0850 } 0851 0852 Settings().setValue(QSL("Browser-View-Settings/SideBar"), m_sideBarManager->activeSideBar()); 0853 } 0854 0855 void BrowserWindow::toggleShowMenubar() 0856 { 0857 #ifdef Q_OS_MACOS 0858 // We use one shared global menubar on Mac that can't be hidden 0859 return; 0860 #endif 0861 0862 setUpdatesEnabled(false); 0863 0864 menuBar()->setVisible(!menuBar()->isVisible()); 0865 m_navigationToolbar->setSuperMenuVisible(!menuBar()->isVisible()); 0866 0867 setUpdatesEnabled(true); 0868 0869 Settings().setValue(QSL("Browser-View-Settings/showMenubar"), menuBar()->isVisible()); 0870 0871 // Make sure we show Navigation Toolbar when Menu Bar is hidden 0872 if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) { 0873 toggleShowNavigationToolbar(); 0874 } 0875 } 0876 0877 void BrowserWindow::toggleShowStatusBar() 0878 { 0879 setUpdatesEnabled(false); 0880 0881 m_statusBar->setVisible(!m_statusBar->isVisible()); 0882 0883 setUpdatesEnabled(true); 0884 0885 Settings().setValue(QSL("Browser-View-Settings/showStatusBar"), m_statusBar->isVisible()); 0886 0887 } 0888 0889 void BrowserWindow::toggleShowBookmarksToolbar() 0890 { 0891 setUpdatesEnabled(false); 0892 0893 m_bookmarksToolbar->setVisible(!m_bookmarksToolbar->isVisible()); 0894 0895 setUpdatesEnabled(true); 0896 0897 Settings().setValue(QSL("Browser-View-Settings/showBookmarksToolbar"), m_bookmarksToolbar->isVisible()); 0898 Settings().setValue(QSL("Browser-View-Settings/instantBookmarksToolbar"), false); 0899 } 0900 0901 void BrowserWindow::toggleShowNavigationToolbar() 0902 { 0903 setUpdatesEnabled(false); 0904 0905 m_navigationToolbar->setVisible(!m_navigationToolbar->isVisible()); 0906 0907 setUpdatesEnabled(true); 0908 0909 Settings().setValue(QSL("Browser-View-Settings/showNavigationToolbar"), m_navigationToolbar->isVisible()); 0910 0911 #ifndef Q_OS_MACOS 0912 // Make sure we show Menu Bar when Navigation Toolbar is hidden 0913 if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) { 0914 toggleShowMenubar(); 0915 } 0916 #endif 0917 } 0918 0919 void BrowserWindow::toggleTabsOnTop(bool enable) 0920 { 0921 qzSettings->tabsOnTop = enable; 0922 m_navigationContainer->toggleTabsOnTop(enable); 0923 } 0924 0925 void BrowserWindow::toggleFullScreen() 0926 { 0927 if (m_htmlFullScreenView) { 0928 weView()->triggerPageAction(QWebEnginePage::ExitFullScreen); 0929 return; 0930 } 0931 0932 if (isFullScreen()) { 0933 setWindowState(windowState() & ~Qt::WindowFullScreen); 0934 } else { 0935 setWindowState(windowState() | Qt::WindowFullScreen); 0936 } 0937 } 0938 0939 void BrowserWindow::requestHtmlFullScreen(TabbedWebView *view, bool enable) 0940 { 0941 if (enable) { 0942 setWindowState(windowState() | Qt::WindowFullScreen); 0943 } else { 0944 setWindowState(windowState() & ~Qt::WindowFullScreen); 0945 } 0946 0947 if (m_sideBar) 0948 m_sideBar.data()->setHidden(enable); 0949 0950 m_htmlFullScreenView = enable ? view : nullptr; 0951 } 0952 0953 void BrowserWindow::showWebInspector() 0954 { 0955 if (weView() && weView()->webTab()) { 0956 weView()->webTab()->showWebInspector(); 0957 } 0958 } 0959 0960 void BrowserWindow::toggleWebInspector() 0961 { 0962 if (weView() && weView()->webTab()) { 0963 weView()->webTab()->toggleWebInspector(); 0964 } 0965 } 0966 0967 void BrowserWindow::currentTabChanged() 0968 { 0969 TabbedWebView* view = weView(); 0970 m_navigationToolbar->setCurrentView(view); 0971 0972 if (!view) { 0973 return; 0974 } 0975 0976 const QString title = view->webTab()->title(/*allowEmpty*/true); 0977 if (title.isEmpty()) { 0978 setWindowTitle(tr("Falkon")); 0979 } else { 0980 setWindowTitle(tr("%1 - Falkon").arg(title)); 0981 } 0982 m_ipLabel->setText(view->getIp()); 0983 view->setFocus(); 0984 0985 updateLoadingActions(); 0986 0987 // Setting correct tab order (LocationBar -> WebSearchBar -> WebView) 0988 setTabOrder(locationBar(), m_navigationToolbar->webSearchBar()); 0989 setTabOrder(m_navigationToolbar->webSearchBar(), view); 0990 } 0991 0992 void BrowserWindow::updateLoadingActions() 0993 { 0994 TabbedWebView* view = weView(); 0995 if (!view) { 0996 return; 0997 } 0998 0999 bool isLoading = view->isLoading(); 1000 1001 m_ipLabel->setVisible(!isLoading); 1002 m_progressBar->setVisible(isLoading); 1003 1004 action(QSL("View/Stop"))->setEnabled(isLoading); 1005 action(QSL("View/Reload"))->setEnabled(!isLoading); 1006 1007 if (isLoading) { 1008 m_progressBar->setValue(view->loadingProgress()); 1009 m_navigationToolbar->showStopButton(); 1010 } 1011 else { 1012 m_navigationToolbar->showReloadButton(); 1013 } 1014 } 1015 1016 void BrowserWindow::addDeleteOnCloseWidget(QWidget* widget) 1017 { 1018 if (!m_deleteOnCloseWidgets.contains(widget)) { 1019 m_deleteOnCloseWidgets.append(widget); 1020 } 1021 } 1022 1023 void BrowserWindow::restoreWindow(const SavedWindow &window) 1024 { 1025 restoreState(window.windowState); 1026 restoreGeometry(window.windowGeometry); 1027 restoreUiState(window.windowUiState); 1028 #ifdef QZ_WS_X11 1029 moveToVirtualDesktop(window.virtualDesktop); 1030 #endif 1031 if (!mApp->isTestModeEnabled()) { 1032 show(); // Window has to be visible before adding QWebEngineView's 1033 } 1034 m_tabWidget->restoreState(window.tabs, window.currentTab); 1035 updateStartupFocus(); 1036 } 1037 1038 void BrowserWindow::createToolbarsMenu(QMenu* menu) 1039 { 1040 removeActions(menu->actions()); 1041 menu->clear(); 1042 1043 QAction* action; 1044 1045 #ifndef Q_OS_MACOS 1046 action = menu->addAction(tr("&Menu Bar"), this, &BrowserWindow::toggleShowMenubar); 1047 action->setCheckable(true); 1048 action->setChecked(menuBar()->isVisible()); 1049 #endif 1050 1051 action = menu->addAction(tr("&Navigation Toolbar"), this, &BrowserWindow::toggleShowNavigationToolbar); 1052 action->setCheckable(true); 1053 action->setChecked(m_navigationToolbar->isVisible()); 1054 1055 action = menu->addAction(tr("&Bookmarks Toolbar"), this, &BrowserWindow::toggleShowBookmarksToolbar); 1056 action->setCheckable(true); 1057 action->setChecked(Settings().value(QSL("Browser-View-Settings/showBookmarksToolbar")).toBool()); 1058 1059 menu->addSeparator(); 1060 1061 action = menu->addAction(tr("&Tabs on Top"), this, SLOT(toggleTabsOnTop(bool))); 1062 action->setCheckable(true); 1063 action->setChecked(qzSettings->tabsOnTop); 1064 1065 addActions(menu->actions()); 1066 } 1067 1068 void BrowserWindow::createSidebarsMenu(QMenu* menu) 1069 { 1070 m_sideBarManager->createMenu(menu); 1071 } 1072 1073 void BrowserWindow::createEncodingMenu(QMenu* menu) 1074 { 1075 const QString activeCodecName = mApp->webSettings()->defaultTextEncoding(); 1076 1077 QStringList isoCodecs; 1078 QStringList utfCodecs; 1079 QStringList windowsCodecs; 1080 QStringList isciiCodecs; 1081 QStringList ibmCodecs; 1082 QStringList otherCodecs; 1083 QStringList allCodecs; 1084 1085 const auto mibs = QTextCodec::availableMibs(); 1086 for (const int mib : mibs) { 1087 const QString codecName = QString::fromUtf8(QTextCodec::codecForMib(mib)->name()); 1088 1089 if (!allCodecs.contains(codecName)) 1090 allCodecs.append(codecName); 1091 else 1092 continue; 1093 1094 if (codecName.startsWith(QLatin1String("ISO"))) 1095 isoCodecs.append(codecName); 1096 else if (codecName.startsWith(QLatin1String("UTF"))) 1097 utfCodecs.append(codecName); 1098 else if (codecName.startsWith(QLatin1String("windows"))) 1099 windowsCodecs.append(codecName); 1100 else if (codecName.startsWith(QLatin1String("Iscii"))) 1101 isciiCodecs.append(codecName); 1102 else if (codecName.startsWith(QLatin1String("IBM"))) 1103 ibmCodecs.append(codecName); 1104 else 1105 otherCodecs.append(codecName); 1106 } 1107 1108 if (!menu->isEmpty()) 1109 menu->addSeparator(); 1110 1111 createEncodingSubMenu(QSL("ISO"), isoCodecs, menu); 1112 createEncodingSubMenu(QSL("UTF"), utfCodecs, menu); 1113 createEncodingSubMenu(QSL("Windows"), windowsCodecs, menu); 1114 createEncodingSubMenu(QSL("Iscii"), isciiCodecs, menu); 1115 createEncodingSubMenu(QSL("IBM"), ibmCodecs, menu); 1116 createEncodingSubMenu(tr("Other"), otherCodecs, menu); 1117 } 1118 1119 void BrowserWindow::removeActions(const QList<QAction *> &actions) 1120 { 1121 for (QAction *action : actions) { 1122 removeAction(action); 1123 } 1124 } 1125 1126 void BrowserWindow::addTab() 1127 { 1128 m_tabWidget->addView(QUrl(), Qz::NT_SelectedNewEmptyTab, true); 1129 m_tabWidget->setCurrentTabFresh(true); 1130 1131 if (isFullScreen()) 1132 showNavigationWithFullScreen(); 1133 } 1134 1135 void BrowserWindow::webSearch() 1136 { 1137 m_navigationToolbar->webSearchBar()->setFocus(); 1138 m_navigationToolbar->webSearchBar()->selectAll(); 1139 } 1140 1141 void BrowserWindow::searchOnPage() 1142 { 1143 if (weView() && weView()->webTab()) { 1144 const QString searchText = weView()->page()->selectedText(); 1145 if (!searchText.contains(QL1C('\n'))) { 1146 weView()->webTab()->showSearchToolBar(searchText); 1147 } else { 1148 weView()->webTab()->showSearchToolBar(); 1149 } 1150 } 1151 } 1152 1153 void BrowserWindow::openFile() 1154 { 1155 const QString fileTypes = QSL("%1(*.html *.htm *.shtml *.shtm *.xhtml);;" 1156 "%2(*.png *.jpg *.jpeg *.bmp *.gif *.svg *.tiff);;" 1157 "%3(*.txt);;" 1158 "%4(*.*)").arg(tr("HTML files"), tr("Image files"), tr("Text files"), tr("All files")); 1159 1160 const QString filePath = QzTools::getOpenFileName(QSL("MainWindow-openFile"), this, tr("Open file..."), QDir::homePath(), fileTypes); 1161 1162 if (!filePath.isEmpty()) { 1163 loadAddress(QUrl::fromLocalFile(filePath)); 1164 } 1165 } 1166 1167 void BrowserWindow::openLocation() 1168 { 1169 if (isFullScreen()) { 1170 showNavigationWithFullScreen(); 1171 } 1172 1173 locationBar()->setFocus(); 1174 locationBar()->selectAll(); 1175 } 1176 1177 bool BrowserWindow::fullScreenNavigationVisible() const 1178 { 1179 return m_navigationContainer->isVisible(); 1180 } 1181 1182 void BrowserWindow::showNavigationWithFullScreen() 1183 { 1184 if (m_htmlFullScreenView) 1185 return; 1186 1187 if (m_hideNavigationTimer->isActive()) { 1188 m_hideNavigationTimer->stop(); 1189 } 1190 1191 m_navigationContainer->show(); 1192 } 1193 1194 void BrowserWindow::hideNavigationWithFullScreen() 1195 { 1196 if (m_tabWidget->isCurrentTabFresh()) 1197 return; 1198 1199 if (!m_hideNavigationTimer->isActive()) { 1200 m_hideNavigationTimer->start(); 1201 } 1202 } 1203 1204 void BrowserWindow::hideNavigationSlot() 1205 { 1206 TabbedWebView* view = weView(); 1207 bool mouseInView = view && view->underMouse(); 1208 1209 if (isFullScreen() && mouseInView) { 1210 m_navigationContainer->hide(); 1211 } 1212 } 1213 1214 bool BrowserWindow::event(QEvent *event) 1215 { 1216 if (event->type() == QEvent::WindowStateChange) { 1217 auto *e = static_cast<QWindowStateChangeEvent*>(event); 1218 if (!(e->oldState() & Qt::WindowFullScreen) && windowState() & Qt::WindowFullScreen) { 1219 // Enter fullscreen 1220 m_statusBarVisible = m_statusBar->isVisible(); 1221 #ifndef Q_OS_MACOS 1222 m_menuBarVisible = menuBar()->isVisible(); 1223 menuBar()->hide(); 1224 #endif 1225 m_statusBar->hide(); 1226 1227 m_navigationContainer->hide(); 1228 m_navigationToolbar->enterFullScreen(); 1229 1230 // Show main menu button since menubar is hidden 1231 m_navigationToolbar->setSuperMenuVisible(true); 1232 } 1233 else if (e->oldState() & Qt::WindowFullScreen && !(windowState() & Qt::WindowFullScreen)) { 1234 // Leave fullscreen 1235 m_statusBar->setVisible(m_statusBarVisible); 1236 #ifndef Q_OS_MACOS 1237 menuBar()->setVisible(m_menuBarVisible); 1238 #endif 1239 1240 m_navigationContainer->show(); 1241 m_navigationToolbar->setSuperMenuVisible(!m_menuBarVisible); 1242 m_navigationToolbar->leaveFullScreen(); 1243 m_htmlFullScreenView = nullptr; 1244 } 1245 1246 if (m_hideNavigationTimer) { 1247 m_hideNavigationTimer->stop(); 1248 } 1249 } 1250 1251 return QMainWindow::event(event); 1252 } 1253 1254 void BrowserWindow::resizeEvent(QResizeEvent* event) 1255 { 1256 m_bookmarksToolbar->setMaximumWidth(width()); 1257 1258 QMainWindow::resizeEvent(event); 1259 } 1260 1261 void BrowserWindow::keyPressEvent(QKeyEvent* event) 1262 { 1263 if (mApp->plugins()->processKeyPress(Qz::ON_BrowserWindow, this, event)) { 1264 return; 1265 } 1266 1267 int number = -1; 1268 TabbedWebView* view = weView(); 1269 1270 switch (event->key()) { 1271 case Qt::Key_Back: 1272 if (view) { 1273 view->back(); 1274 event->accept(); 1275 } 1276 break; 1277 1278 case Qt::Key_Forward: 1279 if (view) { 1280 view->forward(); 1281 event->accept(); 1282 } 1283 break; 1284 1285 case Qt::Key_Stop: 1286 if (view) { 1287 view->stop(); 1288 event->accept(); 1289 } 1290 break; 1291 1292 case Qt::Key_Reload: 1293 case Qt::Key_Refresh: 1294 if (view) { 1295 view->reload(); 1296 event->accept(); 1297 } 1298 break; 1299 1300 case Qt::Key_HomePage: 1301 goHome(); 1302 event->accept(); 1303 break; 1304 1305 case Qt::Key_Favorites: 1306 mApp->browsingLibrary()->showBookmarks(this); 1307 event->accept(); 1308 break; 1309 1310 case Qt::Key_Search: 1311 searchOnPage(); 1312 event->accept(); 1313 break; 1314 1315 case Qt::Key_F6: 1316 case Qt::Key_OpenUrl: 1317 openLocation(); 1318 event->accept(); 1319 break; 1320 1321 case Qt::Key_History: 1322 showHistoryManager(); 1323 event->accept(); 1324 break; 1325 1326 case Qt::Key_AddFavorite: 1327 bookmarkPage(); 1328 event->accept(); 1329 break; 1330 1331 case Qt::Key_Tools: 1332 action(QSL("Standard/Preferences"))->trigger(); 1333 event->accept(); 1334 break; 1335 1336 case Qt::Key_Tab: 1337 if (event->modifiers() == Qt::ControlModifier) { 1338 static_cast<QObject*>(m_tabWidget)->event(event); 1339 } 1340 break; 1341 1342 case Qt::Key_Backtab: 1343 if (event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier)) { 1344 static_cast<QObject*>(m_tabWidget)->event(event); 1345 } 1346 break; 1347 1348 case Qt::Key_PageDown: 1349 if (event->modifiers() == Qt::ControlModifier) { 1350 m_tabWidget->nextTab(); 1351 event->accept(); 1352 } 1353 break; 1354 1355 case Qt::Key_PageUp: 1356 if (event->modifiers() == Qt::ControlModifier) { 1357 m_tabWidget->previousTab(); 1358 event->accept(); 1359 } 1360 break; 1361 1362 case Qt::Key_Equal: 1363 if (view && event->modifiers() == Qt::ControlModifier) { 1364 view->zoomIn(); 1365 event->accept(); 1366 } 1367 break; 1368 1369 case Qt::Key_I: 1370 if (event->modifiers() == Qt::ControlModifier) { 1371 action(QSL("Tools/SiteInfo"))->trigger(); 1372 event->accept(); 1373 } 1374 break; 1375 1376 case Qt::Key_U: 1377 if (event->modifiers() == Qt::ControlModifier) { 1378 action(QSL("View/PageSource"))->trigger(); 1379 event->accept(); 1380 } 1381 break; 1382 1383 case Qt::Key_F: 1384 if (event->modifiers() == Qt::ControlModifier) { 1385 action(QSL("Edit/Find"))->trigger(); 1386 event->accept(); 1387 } 1388 break; 1389 1390 case Qt::Key_Slash: 1391 if (m_useSingleKeyShortcuts) { 1392 action(QSL("Edit/Find"))->trigger(); 1393 event->accept(); 1394 } 1395 break; 1396 1397 case Qt::Key_1: 1398 number = 1; 1399 break; 1400 case Qt::Key_2: 1401 number = 2; 1402 break; 1403 case Qt::Key_3: 1404 number = 3; 1405 break; 1406 case Qt::Key_4: 1407 number = 4; 1408 break; 1409 case Qt::Key_5: 1410 number = 5; 1411 break; 1412 case Qt::Key_6: 1413 number = 6; 1414 break; 1415 case Qt::Key_7: 1416 number = 7; 1417 break; 1418 case Qt::Key_8: 1419 number = 8; 1420 break; 1421 case Qt::Key_9: 1422 number = 9; 1423 break; 1424 1425 default: 1426 break; 1427 } 1428 1429 if (number != -1) { 1430 if (event->modifiers() & Qt::AltModifier && m_useTabNumberShortcuts) { 1431 if (number == 9) { 1432 number = m_tabWidget->count(); 1433 } 1434 m_tabWidget->setCurrentIndex(number - 1); 1435 event->accept(); 1436 return; 1437 } 1438 if (event->modifiers() & Qt::ControlModifier && m_useSpeedDialNumberShortcuts) { 1439 const QUrl url = mApp->plugins()->speedDial()->urlForShortcut(number - 1); 1440 if (url.isValid()) { 1441 loadAddress(url); 1442 event->accept(); 1443 return; 1444 } 1445 } 1446 if (event->modifiers() == Qt::NoModifier && m_useSingleKeyShortcuts) { 1447 if (number == 1) 1448 m_tabWidget->previousTab(); 1449 if (number == 2) 1450 m_tabWidget->nextTab(); 1451 } 1452 } 1453 1454 QMainWindow::keyPressEvent(event); 1455 } 1456 1457 void BrowserWindow::keyReleaseEvent(QKeyEvent* event) 1458 { 1459 if (mApp->plugins()->processKeyRelease(Qz::ON_BrowserWindow, this, event)) { 1460 return; 1461 } 1462 1463 switch (event->key()) { 1464 case Qt::Key_F: 1465 if (event->modifiers() == Qt::ControlModifier) { 1466 action(QSL("Edit/Find"))->trigger(); 1467 event->accept(); 1468 } 1469 break; 1470 1471 default: 1472 break; 1473 } 1474 1475 QMainWindow::keyReleaseEvent(event); 1476 } 1477 1478 void BrowserWindow::closeEvent(QCloseEvent* event) 1479 { 1480 if (mApp->isClosing()) { 1481 saveSettings(); 1482 return; 1483 } 1484 1485 Settings settings; 1486 bool askOnClose = settings.value(QSL("Browser-Tabs-Settings/AskOnClosing"), true).toBool(); 1487 1488 if ((mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) && mApp->windowCount() == 1) { 1489 askOnClose = false; 1490 } 1491 1492 if (askOnClose && m_tabWidget->normalTabsCount() > 1) { 1493 CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, this); 1494 dialog.setDefaultButton(QMessageBox::No); 1495 //~ singular There is still %n open tab and your session won't be stored.\nAre you sure you want to close this window? 1496 //~ plural There are still %n open tabs and your session won't be stored.\nAre you sure you want to close this window? 1497 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())); 1498 dialog.setCheckBoxText(tr("Don't ask again")); 1499 dialog.setWindowTitle(tr("There are still open tabs")); 1500 dialog.setIcon(QMessageBox::Warning); 1501 1502 if (dialog.exec() != QMessageBox::Yes) { 1503 event->ignore(); 1504 return; 1505 } 1506 1507 if (dialog.isChecked()) { 1508 settings.setValue(QSL("Browser-Tabs-Settings/AskOnClosing"), false); 1509 } 1510 } 1511 1512 Q_EMIT aboutToClose(); 1513 1514 saveSettings(); 1515 mApp->closedWindowsManager()->saveWindow(this); 1516 1517 #ifndef Q_OS_MACOS 1518 if (mApp->windowCount() == 1) 1519 mApp->quitApplication(); 1520 #endif 1521 1522 event->accept(); 1523 } 1524 1525 void BrowserWindow::closeWindow() 1526 { 1527 #ifdef Q_OS_MACOS 1528 close(); 1529 return; 1530 #endif 1531 1532 if (mApp->windowCount() > 1) { 1533 close(); 1534 } 1535 } 1536 1537 void BrowserWindow::saveSettings() 1538 { 1539 if (mApp->isPrivate()) { 1540 return; 1541 } 1542 1543 Settings settings; 1544 settings.beginGroup(QSL("Browser-View-Settings")); 1545 settings.setValue(QSL("WindowGeometry"), saveGeometry()); 1546 1547 const auto state = saveUiState(); 1548 for (auto it = state.constBegin(); it != state.constEnd(); ++it) { 1549 settings.setValue(it.key(), it.value()); 1550 } 1551 1552 settings.endGroup(); 1553 } 1554 1555 void BrowserWindow::closeTab() 1556 { 1557 // Don't close pinned tabs with keyboard shortcuts (Ctrl+W, Ctrl+F4) 1558 if (weView() && !weView()->webTab()->isPinned()) { 1559 m_tabWidget->requestCloseTab(); 1560 } 1561 } 1562 1563 #ifdef QZ_WS_X11 1564 static xcb_connection_t *getXcbConnection() 1565 { 1566 const QNativeInterface::QX11Application *x11App = qApp->nativeInterface<QNativeInterface::QX11Application>(); 1567 if (x11App == nullptr) 1568 return nullptr; 1569 return x11App->connection(); 1570 } 1571 1572 int BrowserWindow::getCurrentVirtualDesktop() const 1573 { 1574 if (QGuiApplication::platformName() != QL1S("xcb")) 1575 return 0; 1576 1577 xcb_connection_t *connection = getXcbConnection(); 1578 if (connection == nullptr) 1579 return 0; 1580 1581 xcb_intern_atom_cookie_t intern_atom; 1582 xcb_intern_atom_reply_t *atom_reply = nullptr; 1583 xcb_atom_t atom; 1584 xcb_get_property_cookie_t cookie; 1585 xcb_get_property_reply_t *reply = nullptr; 1586 uint32_t value; 1587 1588 intern_atom = xcb_intern_atom(connection, false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP"); 1589 atom_reply = xcb_intern_atom_reply(connection, intern_atom, nullptr); 1590 1591 if (!atom_reply) 1592 goto error; 1593 1594 atom = atom_reply->atom; 1595 1596 cookie = xcb_get_property(connection, false, winId(), atom, XCB_ATOM_CARDINAL, 0, 1); 1597 reply = xcb_get_property_reply(connection, cookie, nullptr); 1598 1599 if (!reply || reply->type != XCB_ATOM_CARDINAL || reply->value_len != 1 || reply->format != sizeof(uint32_t) * 8) 1600 goto error; 1601 1602 value = *reinterpret_cast<uint32_t*>(xcb_get_property_value(reply)); 1603 1604 free(reply); 1605 free(atom_reply); 1606 return value; 1607 1608 error: 1609 free(reply); 1610 free(atom_reply); 1611 return 0; 1612 } 1613 1614 void BrowserWindow::moveToVirtualDesktop(int desktopId) 1615 { 1616 if (QGuiApplication::platformName() != QL1S("xcb")) 1617 return; 1618 1619 // Don't move when window is already visible or it is first app window 1620 if (desktopId < 0 || isVisible() || m_windowType == Qz::BW_FirstAppWindow) 1621 return; 1622 1623 xcb_connection_t *connection = getXcbConnection(); 1624 if (connection == nullptr) 1625 return; 1626 1627 xcb_intern_atom_cookie_t intern_atom; 1628 xcb_intern_atom_reply_t *atom_reply = nullptr; 1629 xcb_atom_t atom; 1630 1631 intern_atom = xcb_intern_atom(connection, false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP"); 1632 atom_reply = xcb_intern_atom_reply(connection, intern_atom, nullptr); 1633 1634 if (!atom_reply) 1635 goto error; 1636 1637 atom = atom_reply->atom; 1638 1639 xcb_change_property(connection, XCB_PROP_MODE_REPLACE, winId(), atom, 1640 XCB_ATOM_CARDINAL, 32, 1, (const void*) &desktopId); 1641 1642 error: 1643 free(atom_reply); 1644 } 1645 #endif