1 /* ============================================================
2 * Falkon - Qt web browser
3 * Copyright (C) 2010-2018 David Rosca <nowrep@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * ============================================================ */
18 #include "browserwindow.h"
19 #include "tabwidget.h"
20 #include "tabbar.h"
21 #include "webpage.h"
22 #include "tabbedwebview.h"
23 #include "lineedit.h"
24 #include "history.h"
25 #include "locationbar.h"
26 #include "websearchbar.h"
27 #include "pluginproxy.h"
28 #include "sidebar.h"
29 #include "cookiejar.h"
30 #include "cookiemanager.h"
31 #include "bookmarkstoolbar.h"
32 #include "clearprivatedata.h"
33 #include "autofill.h"
34 #include "mainapplication.h"
35 #include "checkboxdialog.h"
36 #include "clickablelabel.h"
37 #include "docktitlebarwidget.h"
38 #include "iconprovider.h"
39 #include "progressbar.h"
40 #include "closedwindowsmanager.h"
41 #include "statusbar.h"
42 #include "browsinglibrary.h"
43 #include "navigationbar.h"
44 #include "bookmarksimport/bookmarksimportdialog.h"
45 #include "qztools.h"
46 #include "reloadstopbutton.h"
47 #include "enhancedmenu.h"
48 #include "navigationcontainer.h"
49 #include "settings.h"
50 #include "qzsettings.h"
51 #include "speeddial.h"
52 #include "menubar.h"
53 #include "bookmarkstools.h"
54 #include "bookmarksmenu.h"
55 #include "historymenu.h"
56 #include "mainmenu.h"
57 #include "downloadsbutton.h"
58 #include "tabmodel.h"
59 #include "tabmrumodel.h"
60
61 #include <algorithm>
62
63 #include <QKeyEvent>
64 #include <QSplitter>
65 #include <QMenuBar>
66 #include <QTimer>
67 #include <QShortcut>
68 #include <QStackedWidget>
69 #include <QTextCodec>
70 #include <QFileDialog>
71 #include <QDesktopServices>
72 #include <QWebEngineHistory>
73 #include <QWebEngineSettings>
74 #include <QMessageBox>
75 #include <QDesktopWidget>
76 #include <QToolTip>
77 #include <QScrollArea>
78 #include <QCollator>
79 #include <QTemporaryFile>
80
81 #ifdef QZ_WS_X11
82 #include <QX11Info>
83 #include <xcb/xcb.h>
84 #include <xcb/xcb_atom.h>
85 #endif
86
87 static const int savedWindowVersion = 2;
88
SavedWindow()89 BrowserWindow::SavedWindow::SavedWindow()
90 {
91 }
92
SavedWindow(BrowserWindow * window)93 BrowserWindow::SavedWindow::SavedWindow(BrowserWindow *window)
94 {
95 windowState = window->isFullScreen() ? QByteArray() : window->saveState();
96 windowGeometry = window->saveGeometry();
97 windowUiState = window->saveUiState();
98 #ifdef QZ_WS_X11
99 virtualDesktop = window->getCurrentVirtualDesktop();
100 #endif
101
102 const int tabsCount = window->tabCount();
103 tabs.reserve(tabsCount);
104 for (int i = 0; i < tabsCount; ++i) {
105 TabbedWebView *webView = window->weView(i);
106 if (!webView) {
107 continue;
108 }
109 WebTab* webTab = webView->webTab();
110 if (!webTab) {
111 continue;
112 }
113 WebTab::SavedTab tab(webTab);
114 if (!tab.isValid()) {
115 continue;
116 }
117 if (webTab->isCurrentTab()) {
118 currentTab = tabs.size();
119 }
120 tabs.append(tab);
121 }
122 }
123
isValid() const124 bool BrowserWindow::SavedWindow::isValid() const
125 {
126 for (const WebTab::SavedTab &tab : qAsConst(tabs)) {
127 if (!tab.isValid()) {
128 return false;
129 }
130 }
131 return currentTab > -1;
132 }
133
clear()134 void BrowserWindow::SavedWindow::clear()
135 {
136 windowState.clear();
137 windowGeometry.clear();
138 virtualDesktop = -1;
139 currentTab = -1;
140 tabs.clear();
141 }
142
operator <<(QDataStream & stream,const BrowserWindow::SavedWindow & window)143 QDataStream &operator<<(QDataStream &stream, const BrowserWindow::SavedWindow &window)
144 {
145 stream << savedWindowVersion;
146 stream << window.windowState;
147 stream << window.windowGeometry;
148 stream << window.virtualDesktop;
149 stream << window.currentTab;
150 stream << window.tabs.count();
151
152 for (int i = 0; i < window.tabs.count(); ++i) {
153 stream << window.tabs.at(i);
154 }
155
156 stream << window.windowUiState;
157
158 return stream;
159 }
160
operator >>(QDataStream & stream,BrowserWindow::SavedWindow & window)161 QDataStream &operator>>(QDataStream &stream, BrowserWindow::SavedWindow &window)
162 {
163 int version;
164 stream >> version;
165
166 if (version < 1) {
167 return stream;
168 }
169
170 stream >> window.windowState;
171 stream >> window.windowGeometry;
172 stream >> window.virtualDesktop;
173 stream >> window.currentTab;
174
175 int tabsCount = -1;
176 stream >> tabsCount;
177 window.tabs.reserve(tabsCount);
178
179 for (int i = 0; i < tabsCount; ++i) {
180 WebTab::SavedTab tab;
181 stream >> tab;
182 window.tabs.append(tab);
183 }
184
185 if (version >= 2) {
186 stream >> window.windowUiState;
187 }
188
189 return stream;
190 }
191
BrowserWindow(Qz::BrowserWindowType type,const QUrl & startUrl)192 BrowserWindow::BrowserWindow(Qz::BrowserWindowType type, const QUrl &startUrl)
193 : QMainWindow(nullptr)
194 , m_startUrl(startUrl)
195 , m_windowType(type)
196 , m_startTab(nullptr)
197 , m_startPage(nullptr)
198 , m_sideBarManager(new SideBarManager(this))
199 , m_hideNavigationTimer(nullptr)
200 {
201 setAttribute(Qt::WA_DeleteOnClose);
202 setAttribute(Qt::WA_DontCreateNativeAncestors);
203
204 setObjectName(QSL("mainwindow"));
205 setWindowTitle(tr("Falkon"));
206 setProperty("private", mApp->isPrivate());
207
208 setupUi();
209 setupMenu();
210
211 m_hideNavigationTimer = new QTimer(this);
212 m_hideNavigationTimer->setInterval(1000);
213 m_hideNavigationTimer->setSingleShot(true);
214 connect(m_hideNavigationTimer, &QTimer::timeout, this, &BrowserWindow::hideNavigationSlot);
215
216 connect(mApp, &MainApplication::settingsReloaded, this, &BrowserWindow::loadSettings);
217
218 QTimer::singleShot(0, this, &BrowserWindow::postLaunch);
219
220 if (mApp->isPrivate()) {
221 QzTools::setWmClass(QSL("Falkon Browser (Private Window)"), this);
222 }
223 else {
224 QzTools::setWmClass(QSL("Falkon Browser"), this);
225 }
226 }
227
~BrowserWindow()228 BrowserWindow::~BrowserWindow()
229 {
230 mApp->plugins()->emitMainWindowDeleted(this);
231
232 for (const QPointer<QWidget> &pointer : qAsConst(m_deleteOnCloseWidgets)) {
233 if (pointer) {
234 pointer->deleteLater();
235 }
236 }
237 }
238
setStartTab(WebTab * tab)239 void BrowserWindow::setStartTab(WebTab* tab)
240 {
241 m_startTab = tab;
242 }
243
setStartPage(WebPage * page)244 void BrowserWindow::setStartPage(WebPage *page)
245 {
246 m_startPage = page;
247 }
248
postLaunch()249 void BrowserWindow::postLaunch()
250 {
251 loadSettings();
252
253 bool addTab = true;
254 QUrl startUrl;
255
256 switch (mApp->afterLaunch()) {
257 case MainApplication::OpenBlankPage:
258 startUrl = QUrl();
259 break;
260
261 case MainApplication::OpenSpeedDial:
262 startUrl = QUrl(QSL("falkon:speeddial"));
263 break;
264
265 case MainApplication::OpenHomePage:
266 case MainApplication::RestoreSession:
267 case MainApplication::SelectSession:
268 startUrl = m_homepage;
269 break;
270
271 default:
272 break;
273 }
274
275 if (!mApp->isTestModeEnabled()) {
276 show();
277 }
278
279 switch (m_windowType) {
280 case Qz::BW_FirstAppWindow:
281 if (mApp->isStartingAfterCrash()) {
282 addTab = false;
283 startUrl.clear();
284 m_tabWidget->addView(QUrl(QSL("falkon:restore")), Qz::NT_CleanSelectedTabAtTheEnd);
285 }
286 else if (mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) {
287 addTab = m_tabWidget->count() <= 0;
288 }
289 break;
290
291 case Qz::BW_NewWindow:
292 case Qz::BW_MacFirstWindow:
293 addTab = true;
294 break;
295
296 case Qz::BW_OtherRestoredWindow:
297 addTab = false;
298 break;
299 }
300
301 if (!m_startUrl.isEmpty()) {
302 startUrl = m_startUrl;
303 addTab = true;
304 }
305
306 if (m_startTab) {
307 addTab = false;
308 m_tabWidget->addView(m_startTab, Qz::NT_SelectedTab);
309 }
310
311 if (m_startPage) {
312 addTab = false;
313 m_tabWidget->addView(QUrl());
314 weView()->setPage(m_startPage);
315 }
316
317 if (addTab) {
318 m_tabWidget->addView(startUrl, Qz::NT_CleanSelectedTabAtTheEnd);
319
320 if (startUrl.isEmpty() || startUrl.toString() == QLatin1String("falkon:speeddial")) {
321 locationBar()->setFocus();
322 }
323 }
324
325 // Something went really wrong .. add one tab
326 if (m_tabWidget->count() <= 0) {
327 m_tabWidget->addView(m_homepage, Qz::NT_SelectedTabAtTheEnd);
328 }
329
330 mApp->plugins()->emitMainWindowCreated(this);
331 emit startingCompleted();
332
333 raise();
334 activateWindow();
335 updateStartupFocus();
336 }
337
setupUi()338 void BrowserWindow::setupUi()
339 {
340 Settings settings;
341 settings.beginGroup(QSL("Browser-View-Settings"));
342 const QByteArray windowGeometry = settings.value(QSL("WindowGeometry")).toByteArray();
343
344 const QStringList keys = {
345 QSL("LocationBarWidth"),
346 QSL("WebSearchBarWidth"),
347 QSL("SideBarWidth"),
348 QSL("WebViewWidth"),
349 QSL("SideBar")
350 };
351 QHash<QString, QVariant> uiState;
352 for (const QString &key : keys) {
353 if (settings.contains(key)) {
354 uiState[key] = settings.value(key);
355 }
356 }
357 settings.endGroup();
358
359 QWidget* widget = new QWidget(this);
360 widget->setCursor(Qt::ArrowCursor);
361 setCentralWidget(widget);
362
363 m_mainLayout = new QVBoxLayout(widget);
364 m_mainLayout->setContentsMargins(0, 0, 0, 0);
365 m_mainLayout->setSpacing(0);
366 m_mainSplitter = new QSplitter(this);
367 m_mainSplitter->setObjectName(QSL("sidebar-splitter"));
368 m_tabWidget = new TabWidget(this);
369 m_superMenu = new QMenu(this);
370 m_navigationToolbar = new NavigationBar(this);
371 m_bookmarksToolbar = new BookmarksToolbar(this);
372
373 m_tabModel = new TabModel(this, this);
374 m_tabMruModel = new TabMruModel(this, this);
375 m_tabMruModel->setSourceModel(m_tabModel);
376
377 m_navigationContainer = new NavigationContainer(this);
378 m_navigationContainer->addWidget(m_navigationToolbar);
379 m_navigationContainer->addWidget(m_bookmarksToolbar);
380 m_navigationContainer->setTabBar(m_tabWidget->tabBar());
381
382 m_mainSplitter->addWidget(m_tabWidget);
383 m_mainSplitter->setCollapsible(0, false);
384
385 m_mainLayout->addWidget(m_navigationContainer);
386 m_mainLayout->addWidget(m_mainSplitter);
387
388 m_statusBar = new StatusBar(this);
389 m_statusBar->setObjectName(QSL("mainwindow-statusbar"));
390 m_statusBar->setCursor(Qt::ArrowCursor);
391 setStatusBar(m_statusBar);
392 m_progressBar = new ProgressBar(m_statusBar);
393 m_ipLabel = new QLabel(this);
394 m_ipLabel->setObjectName(QSL("statusbar-ip-label"));
395 m_ipLabel->setToolTip(tr("IP Address of current page"));
396
397 m_statusBar->addPermanentWidget(m_progressBar);
398 m_statusBar->addPermanentWidget(m_ipLabel);
399
400 DownloadsButton *downloadsButton = new DownloadsButton(this);
401 m_statusBar->addButton(downloadsButton);
402 m_navigationToolbar->addToolButton(downloadsButton);
403
404 QDesktopWidget* desktop = mApp->desktop();
405 int windowWidth = desktop->availableGeometry().width() / 1.3;
406 int windowHeight = desktop->availableGeometry().height() / 1.3;
407
408 // Let the WM decides where to put new browser window
409 if (m_windowType != Qz::BW_FirstAppWindow && m_windowType != Qz::BW_MacFirstWindow && mApp->getWindow()) {
410 #ifdef Q_WS_WIN
411 // Windows WM places every new window in the middle of screen .. for some reason
412 QPoint p = mApp->getWindow()->geometry().topLeft();
413 p.setX(p.x() + 30);
414 p.setY(p.y() + 30);
415
416 if (!desktop->availableGeometry(mApp->getWindow()).contains(p)) {
417 p.setX(desktop->availableGeometry(mApp->getWindow()).x() + 30);
418 p.setY(desktop->availableGeometry(mApp->getWindow()).y() + 30);
419 }
420
421 setGeometry(QRect(p, mApp->getWindow()->size()));
422 #else
423 resize(mApp->getWindow()->size());
424 #endif
425 } else if (!restoreGeometry(windowGeometry)) {
426 #ifdef Q_WS_WIN
427 setGeometry(QRect(desktop->availableGeometry(mApp->getWindow()).x() + 30,
428 desktop->availableGeometry(mApp->getWindow()).y() + 30, windowWidth, windowHeight));
429 #else
430 resize(windowWidth, windowHeight);
431 #endif
432 }
433
434 restoreUiState(uiState);
435
436 // Set some sane minimum width
437 setMinimumWidth(300);
438 }
439
setupMenu()440 void BrowserWindow::setupMenu()
441 {
442 #ifdef Q_OS_MACOS
443 static MainMenu* macMainMenu = 0;
444
445 if (!macMainMenu) {
446 macMainMenu = new MainMenu(this, 0);
447 macMainMenu->initMenuBar(new QMenuBar(0));
448 connect(mApp, SIGNAL(activeWindowChanged(BrowserWindow*)), macMainMenu, SLOT(setWindow(BrowserWindow*)));
449 }
450 else {
451 macMainMenu->setWindow(this);
452 }
453
454 m_mainMenu = macMainMenu;
455 #else
456 setMenuBar(new MenuBar(this));
457
458 m_mainMenu = new MainMenu(this, this);
459 m_mainMenu->initMenuBar(menuBar());
460 #endif
461 m_mainMenu->initSuperMenu(m_superMenu);
462
463 // Setup other shortcuts
464 QShortcut* reloadBypassCacheAction = new QShortcut(QKeySequence(QSL("Ctrl+F5")), this);
465 QShortcut* reloadBypassCacheAction2 = new QShortcut(QKeySequence(QSL("Ctrl+Shift+R")), this);
466 connect(reloadBypassCacheAction, &QShortcut::activated, this, &BrowserWindow::reloadBypassCache);
467 connect(reloadBypassCacheAction2, &QShortcut::activated, this, &BrowserWindow::reloadBypassCache);
468
469 QShortcut* closeTabAction = new QShortcut(QKeySequence(QSL("Ctrl+W")), this);
470 QShortcut* closeTabAction2 = new QShortcut(QKeySequence(QSL("Ctrl+F4")), this);
471 connect(closeTabAction, &QShortcut::activated, this, &BrowserWindow::closeTab);
472 connect(closeTabAction2, &QShortcut::activated, this, &BrowserWindow::closeTab);
473
474 QShortcut* reloadAction = new QShortcut(QKeySequence(QSL("Ctrl+R")), this);
475 connect(reloadAction, &QShortcut::activated, this, &BrowserWindow::reload);
476
477 QShortcut* openLocationAction = new QShortcut(QKeySequence(QSL("Alt+D")), this);
478 connect(openLocationAction, &QShortcut::activated, this, &BrowserWindow::openLocation);
479
480 QShortcut* inspectorAction = new QShortcut(QKeySequence(QSL("F12")), this);
481 connect(inspectorAction, &QShortcut::activated, this, &BrowserWindow::toggleWebInspector);
482
483 QShortcut* restoreClosedWindow = new QShortcut(QKeySequence(QSL("Ctrl+Shift+N")), this);
484 connect(restoreClosedWindow, &QShortcut::activated, mApp->closedWindowsManager(), &ClosedWindowsManager::restoreClosedWindow);
485 }
486
updateStartupFocus()487 void BrowserWindow::updateStartupFocus()
488 {
489 QTimer::singleShot(500, this, [this]() {
490 // Scroll to current tab
491 tabWidget()->tabBar()->ensureVisible();
492 // Update focus
493 if (!m_startPage && LocationBar::convertUrlToText(weView()->page()->requestedUrl()).isEmpty())
494 locationBar()->setFocus();
495 else
496 weView()->setFocus();
497 });
498 }
499
createEncodingAction(const QString & codecName,const QString & activeCodecName,QMenu * menu)500 QAction* BrowserWindow::createEncodingAction(const QString &codecName,
501 const QString &activeCodecName, QMenu* menu)
502 {
503 QAction* action = new QAction(codecName, menu);
504 action->setData(codecName);
505 action->setCheckable(true);
506 connect(action, &QAction::triggered, this, &BrowserWindow::changeEncoding);
507 if (activeCodecName.compare(codecName, Qt::CaseInsensitive) == 0) {
508 action->setChecked(true);
509 }
510 return action;
511 }
512
createEncodingSubMenu(const QString & name,QStringList & codecNames,QMenu * menu)513 void BrowserWindow::createEncodingSubMenu(const QString &name, QStringList &codecNames, QMenu* menu)
514 {
515 if (codecNames.isEmpty()) {
516 return;
517 }
518
519 QCollator collator;
520 collator.setNumericMode(true);
521 std::sort(codecNames.begin(), codecNames.end(), [collator](const QString &a, const QString &b) {
522 return collator.compare(a, b) < 0;
523 });
524
525 QMenu* subMenu = new QMenu(name, menu);
526 const QString activeCodecName = mApp->webSettings()->defaultTextEncoding();
527
528 QActionGroup *group = new QActionGroup(subMenu);
529
530 for (const QString &codecName : qAsConst(codecNames)) {
531 QAction *act = createEncodingAction(codecName, activeCodecName, subMenu);
532 group->addAction(act);
533 subMenu->addAction(act);
534 }
535
536 menu->addMenu(subMenu);
537 }
538
saveUiState()539 QHash<QString, QVariant> BrowserWindow::saveUiState()
540 {
541 saveSideBarSettings();
542
543 QHash<QString, QVariant> state;
544 state[QSL("LocationBarWidth")] = m_navigationToolbar->splitter()->sizes().at(0);
545 state[QSL("WebSearchBarWidth")] = m_navigationToolbar->splitter()->sizes().at(1);
546 state[QSL("SideBarWidth")] = m_sideBarWidth;
547 state[QSL("WebViewWidth")] = m_webViewWidth;
548 state[QSL("SideBar")] = m_sideBarManager->activeSideBar();
549 return state;
550 }
551
restoreUiState(const QHash<QString,QVariant> & state)552 void BrowserWindow::restoreUiState(const QHash<QString, QVariant> &state)
553 {
554 const int locationBarWidth = state.value(QSL("LocationBarWidth"), 480).toInt();
555 const int websearchBarWidth = state.value(QSL("WebSearchBarWidth"), 140).toInt();
556 m_navigationToolbar->setSplitterSizes(locationBarWidth, websearchBarWidth);
557
558 m_sideBarWidth = state.value(QSL("SideBarWidth"), 250).toInt();
559 m_webViewWidth = state.value(QSL("WebViewWidth"), 2000).toInt();
560 if (m_sideBar) {
561 m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth});
562 }
563
564 const QString activeSideBar = state.value(QSL("SideBar")).toString();
565 if (activeSideBar.isEmpty() && m_sideBar) {
566 m_sideBar->close();
567 } else {
568 m_sideBarManager->showSideBar(activeSideBar, false);
569 }
570 }
571
loadSettings()572 void BrowserWindow::loadSettings()
573 {
574 Settings settings;
575
576 //Url settings
577 settings.beginGroup(QSL("Web-URL-Settings"));
578 m_homepage = settings.value(QSL("homepage"), QSL("falkon:start")).toUrl();
579 settings.endGroup();
580
581 //Browser Window settings
582 settings.beginGroup(QSL("Browser-View-Settings"));
583 bool showStatusBar = settings.value(QSL("showStatusBar"), false).toBool();
584 bool showBookmarksToolbar = settings.value(QSL("showBookmarksToolbar"), false).toBool();
585 bool showNavigationToolbar = settings.value(QSL("showNavigationToolbar"), true).toBool();
586 bool showMenuBar = settings.value(QSL("showMenubar"), false).toBool();
587
588 // Make sure both menubar and navigationbar are not hidden
589 // Fixes #781
590 if (!showNavigationToolbar) {
591 showMenuBar = true;
592 settings.setValue(QSL("showMenubar"), true);
593 }
594
595 settings.endGroup();
596
597 settings.beginGroup(QSL("Shortcuts"));
598 m_useTabNumberShortcuts = settings.value(QSL("useTabNumberShortcuts"), true).toBool();
599 m_useSpeedDialNumberShortcuts = settings.value(QSL("useSpeedDialNumberShortcuts"), true).toBool();
600 m_useSingleKeyShortcuts = settings.value(QSL("useSingleKeyShortcuts"), false).toBool();
601 settings.endGroup();
602
603 settings.beginGroup(QSL("Web-Browser-Settings"));
604 QAction *quitAction = m_mainMenu->action(QSL("Standard/Quit"));
605 if (settings.value(QSL("closeAppWithCtrlQ"), true).toBool()) {
606 quitAction->setShortcut(QzTools::actionShortcut(QKeySequence::Quit, QKeySequence(QSL("Ctrl+Q"))));
607 } else {
608 quitAction->setShortcut(QKeySequence());
609 }
610 settings.endGroup();
611
612 m_statusBarVisible = showStatusBar;
613 statusBar()->setVisible(!isFullScreen() && showStatusBar);
614 m_bookmarksToolbar->setVisible(showBookmarksToolbar);
615 m_navigationToolbar->setVisible(showNavigationToolbar);
616
617 #ifndef Q_OS_MACOS
618 m_menuBarVisible = showMenuBar;
619 menuBar()->setVisible(!isFullScreen() && showMenuBar);
620 #endif
621
622 m_navigationToolbar->setSuperMenuVisible(isFullScreen() || !showMenuBar);
623 }
624
goForward()625 void BrowserWindow::goForward()
626 {
627 weView()->forward();
628 }
629
reload()630 void BrowserWindow::reload()
631 {
632 weView()->reload();
633 }
634
reloadBypassCache()635 void BrowserWindow::reloadBypassCache()
636 {
637 weView()->reloadBypassCache();
638 }
639
goBack()640 void BrowserWindow::goBack()
641 {
642 weView()->back();
643 }
644
tabCount() const645 int BrowserWindow::tabCount() const
646 {
647 return m_tabWidget->count();
648 }
649
weView() const650 TabbedWebView* BrowserWindow::weView() const
651 {
652 return weView(m_tabWidget->currentIndex());
653 }
654
weView(int index) const655 TabbedWebView* BrowserWindow::weView(int index) const
656 {
657 WebTab* webTab = qobject_cast<WebTab*>(m_tabWidget->widget(index));
658 if (!webTab) {
659 return nullptr;
660 }
661
662 return webTab->webView();
663 }
664
locationBar() const665 LocationBar* BrowserWindow::locationBar() const
666 {
667 return qobject_cast<LocationBar*>(m_tabWidget->locationBars()->currentWidget());
668 }
669
tabWidget() const670 TabWidget* BrowserWindow::tabWidget() const
671 {
672 return m_tabWidget;
673 }
674
bookmarksToolbar() const675 BookmarksToolbar* BrowserWindow::bookmarksToolbar() const
676 {
677 return m_bookmarksToolbar;
678 }
679
statusBar() const680 StatusBar* BrowserWindow::statusBar() const
681 {
682 return m_statusBar;
683 }
684
navigationBar() const685 NavigationBar* BrowserWindow::navigationBar() const
686 {
687 return m_navigationToolbar;
688 }
689
sideBarManager() const690 SideBarManager* BrowserWindow::sideBarManager() const
691 {
692 return m_sideBarManager;
693 }
694
ipLabel() const695 QLabel* BrowserWindow::ipLabel() const
696 {
697 return m_ipLabel;
698 }
699
superMenu() const700 QMenu* BrowserWindow::superMenu() const
701 {
702 return m_superMenu;
703 }
704
homepageUrl() const705 QUrl BrowserWindow::homepageUrl() const
706 {
707 return m_homepage;
708 }
709
windowType() const710 Qz::BrowserWindowType BrowserWindow::windowType() const
711 {
712 return m_windowType;
713 }
714
action(const QString & name) const715 QAction* BrowserWindow::action(const QString &name) const
716 {
717 return m_mainMenu->action(name);
718 }
719
tabModel() const720 TabModel *BrowserWindow::tabModel() const
721 {
722 return m_tabModel;
723 }
724
tabMruModel() const725 TabMruModel *BrowserWindow::tabMruModel() const
726 {
727 return m_tabMruModel;
728 }
729
setWindowTitle(const QString & t)730 void BrowserWindow::setWindowTitle(const QString &t)
731 {
732 QString title = t;
733
734 if (mApp->isPrivate()) {
735 title.append(tr(" (Private Browsing)"));
736 }
737
738 QMainWindow::setWindowTitle(title);
739 }
740
changeEncoding()741 void BrowserWindow::changeEncoding()
742 {
743 if (QAction* action = qobject_cast<QAction*>(sender())) {
744 const QString encoding = action->data().toString();
745 mApp->webSettings()->setDefaultTextEncoding(encoding);
746
747 Settings settings;
748 settings.setValue(QSL("Web-Browser-Settings/DefaultEncoding"), encoding);
749
750 weView()->reload();
751 }
752 }
753
printPage()754 void BrowserWindow::printPage()
755 {
756 weView()->printPage();
757 }
758
bookmarkPage()759 void BrowserWindow::bookmarkPage()
760 {
761 TabbedWebView* view = weView();
762 BookmarksTools::addBookmarkDialog(this, view->url(), view->title());
763 }
764
bookmarkAllTabs()765 void BrowserWindow::bookmarkAllTabs()
766 {
767 BookmarksTools::bookmarkAllTabsDialog(this, m_tabWidget);
768 }
769
addBookmark(const QUrl & url,const QString & title)770 void BrowserWindow::addBookmark(const QUrl &url, const QString &title)
771 {
772 BookmarksTools::addBookmarkDialog(this, url, title);
773 }
774
goHome()775 void BrowserWindow::goHome()
776 {
777 loadAddress(m_homepage);
778 }
779
goHomeInNewTab()780 void BrowserWindow::goHomeInNewTab()
781 {
782 m_tabWidget->addView(m_homepage, Qz::NT_SelectedTab);
783 }
784
loadActionUrl(QObject * obj)785 void BrowserWindow::loadActionUrl(QObject* obj)
786 {
787 if (!obj) {
788 obj = sender();
789 }
790
791 if (QAction* action = qobject_cast<QAction*>(obj)) {
792 loadAddress(action->data().toUrl());
793 }
794 }
795
loadActionUrlInNewTab(QObject * obj)796 void BrowserWindow::loadActionUrlInNewTab(QObject* obj)
797 {
798 if (!obj) {
799 obj = sender();
800 }
801
802 if (QAction* action = qobject_cast<QAction*>(obj)) {
803 m_tabWidget->addView(action->data().toUrl(), Qz::NT_SelectedTabAtTheEnd);
804 }
805 }
806
loadAddress(const QUrl & url)807 void BrowserWindow::loadAddress(const QUrl &url)
808 {
809 if (weView()->webTab()->isPinned()) {
810 int index = m_tabWidget->addView(url, qzSettings->newTabPosition);
811 weView(index)->setFocus();
812 } else {
813 weView()->setFocus();
814 weView()->load(LoadRequest(url));
815 }
816 }
817
showHistoryManager()818 void BrowserWindow::showHistoryManager()
819 {
820 mApp->browsingLibrary()->showHistory(this);
821 }
822
showSource(WebView * view)823 void BrowserWindow::showSource(WebView *view)
824 {
825 if (!view)
826 view = weView();
827 view->showSource();
828 }
829
addSideBar()830 SideBar* BrowserWindow::addSideBar()
831 {
832 if (m_sideBar) {
833 return m_sideBar.data();
834 }
835
836 m_sideBar = new SideBar(m_sideBarManager, this);
837
838 m_mainSplitter->insertWidget(0, m_sideBar.data());
839 m_mainSplitter->setCollapsible(0, false);
840 m_mainSplitter->setSizes({m_sideBarWidth, m_webViewWidth});
841
842 return m_sideBar.data();
843 }
844
saveSideBarSettings()845 void BrowserWindow::saveSideBarSettings()
846 {
847 if (m_sideBar) {
848 // That +1 is important here, without it, the sidebar width would
849 // decrease by 1 pixel every close
850 m_sideBarWidth = m_mainSplitter->sizes().at(0) + 1;
851 m_webViewWidth = width() - m_sideBarWidth;
852 }
853
854 Settings().setValue(QSL("Browser-View-Settings/SideBar"), m_sideBarManager->activeSideBar());
855 }
856
toggleShowMenubar()857 void BrowserWindow::toggleShowMenubar()
858 {
859 #ifdef Q_OS_MACOS
860 // We use one shared global menubar on Mac that can't be hidden
861 return;
862 #endif
863
864 setUpdatesEnabled(false);
865
866 menuBar()->setVisible(!menuBar()->isVisible());
867 m_navigationToolbar->setSuperMenuVisible(!menuBar()->isVisible());
868
869 setUpdatesEnabled(true);
870
871 Settings().setValue(QSL("Browser-View-Settings/showMenubar"), menuBar()->isVisible());
872
873 // Make sure we show Navigation Toolbar when Menu Bar is hidden
874 if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) {
875 toggleShowNavigationToolbar();
876 }
877 }
878
toggleShowStatusBar()879 void BrowserWindow::toggleShowStatusBar()
880 {
881 setUpdatesEnabled(false);
882
883 m_statusBar->setVisible(!m_statusBar->isVisible());
884
885 setUpdatesEnabled(true);
886
887 Settings().setValue(QSL("Browser-View-Settings/showStatusBar"), m_statusBar->isVisible());
888
889 }
890
toggleShowBookmarksToolbar()891 void BrowserWindow::toggleShowBookmarksToolbar()
892 {
893 setUpdatesEnabled(false);
894
895 m_bookmarksToolbar->setVisible(!m_bookmarksToolbar->isVisible());
896
897 setUpdatesEnabled(true);
898
899 Settings().setValue(QSL("Browser-View-Settings/showBookmarksToolbar"), m_bookmarksToolbar->isVisible());
900 Settings().setValue(QSL("Browser-View-Settings/instantBookmarksToolbar"), false);
901 }
902
toggleShowNavigationToolbar()903 void BrowserWindow::toggleShowNavigationToolbar()
904 {
905 setUpdatesEnabled(false);
906
907 m_navigationToolbar->setVisible(!m_navigationToolbar->isVisible());
908
909 setUpdatesEnabled(true);
910
911 Settings().setValue(QSL("Browser-View-Settings/showNavigationToolbar"), m_navigationToolbar->isVisible());
912
913 #ifndef Q_OS_MACOS
914 // Make sure we show Menu Bar when Navigation Toolbar is hidden
915 if (!m_navigationToolbar->isVisible() && !menuBar()->isVisible()) {
916 toggleShowMenubar();
917 }
918 #endif
919 }
920
toggleTabsOnTop(bool enable)921 void BrowserWindow::toggleTabsOnTop(bool enable)
922 {
923 qzSettings->tabsOnTop = enable;
924 m_navigationContainer->toggleTabsOnTop(enable);
925 }
926
toggleFullScreen()927 void BrowserWindow::toggleFullScreen()
928 {
929 if (m_htmlFullScreenView) {
930 weView()->triggerPageAction(QWebEnginePage::ExitFullScreen);
931 return;
932 }
933
934 if (isFullScreen()) {
935 setWindowState(windowState() & ~Qt::WindowFullScreen);
936 } else {
937 setWindowState(windowState() | Qt::WindowFullScreen);
938 }
939 }
940
requestHtmlFullScreen(TabbedWebView * view,bool enable)941 void BrowserWindow::requestHtmlFullScreen(TabbedWebView *view, bool enable)
942 {
943 if (enable) {
944 setWindowState(windowState() | Qt::WindowFullScreen);
945 } else {
946 setWindowState(windowState() & ~Qt::WindowFullScreen);
947 }
948
949 if (m_sideBar)
950 m_sideBar.data()->setHidden(enable);
951
952 m_htmlFullScreenView = enable ? view : nullptr;
953 }
954
showWebInspector()955 void BrowserWindow::showWebInspector()
956 {
957 if (weView() && weView()->webTab()) {
958 weView()->webTab()->showWebInspector();
959 }
960 }
961
toggleWebInspector()962 void BrowserWindow::toggleWebInspector()
963 {
964 if (weView() && weView()->webTab()) {
965 weView()->webTab()->toggleWebInspector();
966 }
967 }
968
currentTabChanged()969 void BrowserWindow::currentTabChanged()
970 {
971 TabbedWebView* view = weView();
972 m_navigationToolbar->setCurrentView(view);
973
974 if (!view) {
975 return;
976 }
977
978 const QString title = view->webTab()->title(/*allowEmpty*/true);
979 if (title.isEmpty()) {
980 setWindowTitle(tr("Falkon"));
981 } else {
982 setWindowTitle(tr("%1 - Falkon").arg(title));
983 }
984 m_ipLabel->setText(view->getIp());
985 view->setFocus();
986
987 updateLoadingActions();
988
989 // Setting correct tab order (LocationBar -> WebSearchBar -> WebView)
990 setTabOrder(locationBar(), m_navigationToolbar->webSearchBar());
991 setTabOrder(m_navigationToolbar->webSearchBar(), view);
992 }
993
updateLoadingActions()994 void BrowserWindow::updateLoadingActions()
995 {
996 TabbedWebView* view = weView();
997 if (!view) {
998 return;
999 }
1000
1001 bool isLoading = view->isLoading();
1002
1003 m_ipLabel->setVisible(!isLoading);
1004 m_progressBar->setVisible(isLoading);
1005
1006 action(QSL("View/Stop"))->setEnabled(isLoading);
1007 action(QSL("View/Reload"))->setEnabled(!isLoading);
1008
1009 if (isLoading) {
1010 m_progressBar->setValue(view->loadingProgress());
1011 m_navigationToolbar->showStopButton();
1012 }
1013 else {
1014 m_navigationToolbar->showReloadButton();
1015 }
1016 }
1017
addDeleteOnCloseWidget(QWidget * widget)1018 void BrowserWindow::addDeleteOnCloseWidget(QWidget* widget)
1019 {
1020 if (!m_deleteOnCloseWidgets.contains(widget)) {
1021 m_deleteOnCloseWidgets.append(widget);
1022 }
1023 }
1024
restoreWindow(const SavedWindow & window)1025 void BrowserWindow::restoreWindow(const SavedWindow &window)
1026 {
1027 restoreState(window.windowState);
1028 restoreGeometry(window.windowGeometry);
1029 restoreUiState(window.windowUiState);
1030 #ifdef QZ_WS_X11
1031 moveToVirtualDesktop(window.virtualDesktop);
1032 #endif
1033 if (!mApp->isTestModeEnabled()) {
1034 show(); // Window has to be visible before adding QWebEngineView's
1035 }
1036 m_tabWidget->restoreState(window.tabs, window.currentTab);
1037 updateStartupFocus();
1038 }
1039
createToolbarsMenu(QMenu * menu)1040 void BrowserWindow::createToolbarsMenu(QMenu* menu)
1041 {
1042 removeActions(menu->actions());
1043 menu->clear();
1044
1045 QAction* action;
1046
1047 #ifndef Q_OS_MACOS
1048 action = menu->addAction(tr("&Menu Bar"), this, &BrowserWindow::toggleShowMenubar);
1049 action->setCheckable(true);
1050 action->setChecked(menuBar()->isVisible());
1051 #endif
1052
1053 action = menu->addAction(tr("&Navigation Toolbar"), this, &BrowserWindow::toggleShowNavigationToolbar);
1054 action->setCheckable(true);
1055 action->setChecked(m_navigationToolbar->isVisible());
1056
1057 action = menu->addAction(tr("&Bookmarks Toolbar"), this, &BrowserWindow::toggleShowBookmarksToolbar);
1058 action->setCheckable(true);
1059 action->setChecked(Settings().value(QSL("Browser-View-Settings/showBookmarksToolbar")).toBool());
1060
1061 menu->addSeparator();
1062
1063 action = menu->addAction(tr("&Tabs on Top"), this, SLOT(toggleTabsOnTop(bool)));
1064 action->setCheckable(true);
1065 action->setChecked(qzSettings->tabsOnTop);
1066
1067 addActions(menu->actions());
1068 }
1069
createSidebarsMenu(QMenu * menu)1070 void BrowserWindow::createSidebarsMenu(QMenu* menu)
1071 {
1072 m_sideBarManager->createMenu(menu);
1073 }
1074
createEncodingMenu(QMenu * menu)1075 void BrowserWindow::createEncodingMenu(QMenu* menu)
1076 {
1077 const QString activeCodecName = mApp->webSettings()->defaultTextEncoding();
1078
1079 QStringList isoCodecs;
1080 QStringList utfCodecs;
1081 QStringList windowsCodecs;
1082 QStringList isciiCodecs;
1083 QStringList ibmCodecs;
1084 QStringList otherCodecs;
1085 QStringList allCodecs;
1086
1087 const auto mibs = QTextCodec::availableMibs();
1088 for (const int mib : mibs) {
1089 const QString codecName = QString::fromUtf8(QTextCodec::codecForMib(mib)->name());
1090
1091 if (!allCodecs.contains(codecName))
1092 allCodecs.append(codecName);
1093 else
1094 continue;
1095
1096 if (codecName.startsWith(QLatin1String("ISO")))
1097 isoCodecs.append(codecName);
1098 else if (codecName.startsWith(QLatin1String("UTF")))
1099 utfCodecs.append(codecName);
1100 else if (codecName.startsWith(QLatin1String("windows")))
1101 windowsCodecs.append(codecName);
1102 else if (codecName.startsWith(QLatin1String("Iscii")))
1103 isciiCodecs.append(codecName);
1104 else if (codecName.startsWith(QLatin1String("IBM")))
1105 ibmCodecs.append(codecName);
1106 else
1107 otherCodecs.append(codecName);
1108 }
1109
1110 if (!menu->isEmpty())
1111 menu->addSeparator();
1112
1113 createEncodingSubMenu(QSL("ISO"), isoCodecs, menu);
1114 createEncodingSubMenu(QSL("UTF"), utfCodecs, menu);
1115 createEncodingSubMenu(QSL("Windows"), windowsCodecs, menu);
1116 createEncodingSubMenu(QSL("Iscii"), isciiCodecs, menu);
1117 createEncodingSubMenu(QSL("IBM"), ibmCodecs, menu);
1118 createEncodingSubMenu(tr("Other"), otherCodecs, menu);
1119 }
1120
removeActions(const QList<QAction * > & actions)1121 void BrowserWindow::removeActions(const QList<QAction *> &actions)
1122 {
1123 for (QAction *action : actions) {
1124 removeAction(action);
1125 }
1126 }
1127
addTab()1128 void BrowserWindow::addTab()
1129 {
1130 m_tabWidget->addView(QUrl(), Qz::NT_SelectedNewEmptyTab, true);
1131 m_tabWidget->setCurrentTabFresh(true);
1132
1133 if (isFullScreen())
1134 showNavigationWithFullScreen();
1135 }
1136
webSearch()1137 void BrowserWindow::webSearch()
1138 {
1139 m_navigationToolbar->webSearchBar()->setFocus();
1140 m_navigationToolbar->webSearchBar()->selectAll();
1141 }
1142
searchOnPage()1143 void BrowserWindow::searchOnPage()
1144 {
1145 if (weView() && weView()->webTab()) {
1146 const QString searchText = weView()->page()->selectedText();
1147 if (!searchText.contains(QL1C('\n'))) {
1148 weView()->webTab()->showSearchToolBar(searchText);
1149 } else {
1150 weView()->webTab()->showSearchToolBar();
1151 }
1152 }
1153 }
1154
openFile()1155 void BrowserWindow::openFile()
1156 {
1157 const QString fileTypes = QSL("%1(*.html *.htm *.shtml *.shtm *.xhtml);;"
1158 "%2(*.png *.jpg *.jpeg *.bmp *.gif *.svg *.tiff);;"
1159 "%3(*.txt);;"
1160 "%4(*.*)").arg(tr("HTML files"), tr("Image files"), tr("Text files"), tr("All files"));
1161
1162 const QString filePath = QzTools::getOpenFileName(QSL("MainWindow-openFile"), this, tr("Open file..."), QDir::homePath(), fileTypes);
1163
1164 if (!filePath.isEmpty()) {
1165 loadAddress(QUrl::fromLocalFile(filePath));
1166 }
1167 }
1168
openLocation()1169 void BrowserWindow::openLocation()
1170 {
1171 if (isFullScreen()) {
1172 showNavigationWithFullScreen();
1173 }
1174
1175 locationBar()->setFocus();
1176 locationBar()->selectAll();
1177 }
1178
fullScreenNavigationVisible() const1179 bool BrowserWindow::fullScreenNavigationVisible() const
1180 {
1181 return m_navigationContainer->isVisible();
1182 }
1183
showNavigationWithFullScreen()1184 void BrowserWindow::showNavigationWithFullScreen()
1185 {
1186 if (m_htmlFullScreenView)
1187 return;
1188
1189 if (m_hideNavigationTimer->isActive()) {
1190 m_hideNavigationTimer->stop();
1191 }
1192
1193 m_navigationContainer->show();
1194 }
1195
hideNavigationWithFullScreen()1196 void BrowserWindow::hideNavigationWithFullScreen()
1197 {
1198 if (m_tabWidget->isCurrentTabFresh())
1199 return;
1200
1201 if (!m_hideNavigationTimer->isActive()) {
1202 m_hideNavigationTimer->start();
1203 }
1204 }
1205
hideNavigationSlot()1206 void BrowserWindow::hideNavigationSlot()
1207 {
1208 TabbedWebView* view = weView();
1209 bool mouseInView = view && view->underMouse();
1210
1211 if (isFullScreen() && mouseInView) {
1212 m_navigationContainer->hide();
1213 }
1214 }
1215
event(QEvent * event)1216 bool BrowserWindow::event(QEvent *event)
1217 {
1218 if (event->type() == QEvent::WindowStateChange) {
1219 QWindowStateChangeEvent *e = static_cast<QWindowStateChangeEvent*>(event);
1220 if (!(e->oldState() & Qt::WindowFullScreen) && windowState() & Qt::WindowFullScreen) {
1221 // Enter fullscreen
1222 m_statusBarVisible = m_statusBar->isVisible();
1223 #ifndef Q_OS_MACOS
1224 m_menuBarVisible = menuBar()->isVisible();
1225 menuBar()->hide();
1226 #endif
1227 m_statusBar->hide();
1228
1229 m_navigationContainer->hide();
1230 m_navigationToolbar->enterFullScreen();
1231
1232 // Show main menu button since menubar is hidden
1233 m_navigationToolbar->setSuperMenuVisible(true);
1234 }
1235 else if (e->oldState() & Qt::WindowFullScreen && !(windowState() & Qt::WindowFullScreen)) {
1236 // Leave fullscreen
1237 m_statusBar->setVisible(m_statusBarVisible);
1238 #ifndef Q_OS_MACOS
1239 menuBar()->setVisible(m_menuBarVisible);
1240 #endif
1241
1242 m_navigationContainer->show();
1243 m_navigationToolbar->setSuperMenuVisible(!m_menuBarVisible);
1244 m_navigationToolbar->leaveFullScreen();
1245 m_htmlFullScreenView = nullptr;
1246 }
1247
1248 if (m_hideNavigationTimer) {
1249 m_hideNavigationTimer->stop();
1250 }
1251 }
1252
1253 return QMainWindow::event(event);
1254 }
1255
resizeEvent(QResizeEvent * event)1256 void BrowserWindow::resizeEvent(QResizeEvent* event)
1257 {
1258 m_bookmarksToolbar->setMaximumWidth(width());
1259
1260 QMainWindow::resizeEvent(event);
1261 }
1262
keyPressEvent(QKeyEvent * event)1263 void BrowserWindow::keyPressEvent(QKeyEvent* event)
1264 {
1265 if (mApp->plugins()->processKeyPress(Qz::ON_BrowserWindow, this, event)) {
1266 return;
1267 }
1268
1269 int number = -1;
1270 TabbedWebView* view = weView();
1271
1272 switch (event->key()) {
1273 case Qt::Key_Back:
1274 if (view) {
1275 view->back();
1276 event->accept();
1277 }
1278 break;
1279
1280 case Qt::Key_Forward:
1281 if (view) {
1282 view->forward();
1283 event->accept();
1284 }
1285 break;
1286
1287 case Qt::Key_Stop:
1288 if (view) {
1289 view->stop();
1290 event->accept();
1291 }
1292 break;
1293
1294 case Qt::Key_Reload:
1295 case Qt::Key_Refresh:
1296 if (view) {
1297 view->reload();
1298 event->accept();
1299 }
1300 break;
1301
1302 case Qt::Key_HomePage:
1303 goHome();
1304 event->accept();
1305 break;
1306
1307 case Qt::Key_Favorites:
1308 mApp->browsingLibrary()->showBookmarks(this);
1309 event->accept();
1310 break;
1311
1312 case Qt::Key_Search:
1313 searchOnPage();
1314 event->accept();
1315 break;
1316
1317 case Qt::Key_F6:
1318 case Qt::Key_OpenUrl:
1319 openLocation();
1320 event->accept();
1321 break;
1322
1323 case Qt::Key_History:
1324 showHistoryManager();
1325 event->accept();
1326 break;
1327
1328 case Qt::Key_AddFavorite:
1329 bookmarkPage();
1330 event->accept();
1331 break;
1332
1333 case Qt::Key_News:
1334 action(QSL("Tools/RssReader"))->trigger();
1335 event->accept();
1336 break;
1337
1338 case Qt::Key_Tools:
1339 action(QSL("Standard/Preferences"))->trigger();
1340 event->accept();
1341 break;
1342
1343 case Qt::Key_Tab:
1344 if (event->modifiers() == Qt::ControlModifier) {
1345 static_cast<QObject*>(m_tabWidget)->event(event);
1346 }
1347 break;
1348
1349 case Qt::Key_Backtab:
1350 if (event->modifiers() == (Qt::ControlModifier + Qt::ShiftModifier)) {
1351 static_cast<QObject*>(m_tabWidget)->event(event);
1352 }
1353 break;
1354
1355 case Qt::Key_PageDown:
1356 if (event->modifiers() == Qt::ControlModifier) {
1357 m_tabWidget->nextTab();
1358 event->accept();
1359 }
1360 break;
1361
1362 case Qt::Key_PageUp:
1363 if (event->modifiers() == Qt::ControlModifier) {
1364 m_tabWidget->previousTab();
1365 event->accept();
1366 }
1367 break;
1368
1369 case Qt::Key_Equal:
1370 if (view && event->modifiers() == Qt::ControlModifier) {
1371 view->zoomIn();
1372 event->accept();
1373 }
1374 break;
1375
1376 case Qt::Key_I:
1377 if (event->modifiers() == Qt::ControlModifier) {
1378 action(QSL("Tools/SiteInfo"))->trigger();
1379 event->accept();
1380 }
1381 break;
1382
1383 case Qt::Key_U:
1384 if (event->modifiers() == Qt::ControlModifier) {
1385 action(QSL("View/PageSource"))->trigger();
1386 event->accept();
1387 }
1388 break;
1389
1390 case Qt::Key_F:
1391 if (event->modifiers() == Qt::ControlModifier) {
1392 action(QSL("Edit/Find"))->trigger();
1393 event->accept();
1394 }
1395 break;
1396
1397 case Qt::Key_Slash:
1398 if (m_useSingleKeyShortcuts) {
1399 action(QSL("Edit/Find"))->trigger();
1400 event->accept();
1401 }
1402 break;
1403
1404 case Qt::Key_1:
1405 number = 1;
1406 break;
1407 case Qt::Key_2:
1408 number = 2;
1409 break;
1410 case Qt::Key_3:
1411 number = 3;
1412 break;
1413 case Qt::Key_4:
1414 number = 4;
1415 break;
1416 case Qt::Key_5:
1417 number = 5;
1418 break;
1419 case Qt::Key_6:
1420 number = 6;
1421 break;
1422 case Qt::Key_7:
1423 number = 7;
1424 break;
1425 case Qt::Key_8:
1426 number = 8;
1427 break;
1428 case Qt::Key_9:
1429 number = 9;
1430 break;
1431
1432 default:
1433 break;
1434 }
1435
1436 if (number != -1) {
1437 if (event->modifiers() & Qt::AltModifier && m_useTabNumberShortcuts) {
1438 if (number == 9) {
1439 number = m_tabWidget->count();
1440 }
1441 m_tabWidget->setCurrentIndex(number - 1);
1442 event->accept();
1443 return;
1444 }
1445 if (event->modifiers() & Qt::ControlModifier && m_useSpeedDialNumberShortcuts) {
1446 const QUrl url = mApp->plugins()->speedDial()->urlForShortcut(number - 1);
1447 if (url.isValid()) {
1448 loadAddress(url);
1449 event->accept();
1450 return;
1451 }
1452 }
1453 if (event->modifiers() == Qt::NoModifier && m_useSingleKeyShortcuts) {
1454 if (number == 1)
1455 m_tabWidget->previousTab();
1456 if (number == 2)
1457 m_tabWidget->nextTab();
1458 }
1459 }
1460
1461 QMainWindow::keyPressEvent(event);
1462 }
1463
keyReleaseEvent(QKeyEvent * event)1464 void BrowserWindow::keyReleaseEvent(QKeyEvent* event)
1465 {
1466 if (mApp->plugins()->processKeyRelease(Qz::ON_BrowserWindow, this, event)) {
1467 return;
1468 }
1469
1470 switch (event->key()) {
1471 case Qt::Key_F:
1472 if (event->modifiers() == Qt::ControlModifier) {
1473 action(QSL("Edit/Find"))->trigger();
1474 event->accept();
1475 }
1476 break;
1477
1478 default:
1479 break;
1480 }
1481
1482 QMainWindow::keyReleaseEvent(event);
1483 }
1484
closeEvent(QCloseEvent * event)1485 void BrowserWindow::closeEvent(QCloseEvent* event)
1486 {
1487 if (mApp->isClosing()) {
1488 saveSettings();
1489 return;
1490 }
1491
1492 Settings settings;
1493 bool askOnClose = settings.value(QSL("Browser-Tabs-Settings/AskOnClosing"), true).toBool();
1494
1495 if ((mApp->afterLaunch() == MainApplication::SelectSession || mApp->afterLaunch() == MainApplication::RestoreSession) && mApp->windowCount() == 1) {
1496 askOnClose = false;
1497 }
1498
1499 if (askOnClose && m_tabWidget->normalTabsCount() > 1) {
1500 CheckBoxDialog dialog(QMessageBox::Yes | QMessageBox::No, this);
1501 dialog.setDefaultButton(QMessageBox::No);
1502 //~ singular There is still %n open tab and your session won't be stored.\nAre you sure you want to close this window?
1503 //~ plural There are still %n open tabs and your session won't be stored.\nAre you sure you want to close this window?
1504 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()));
1505 dialog.setCheckBoxText(tr("Don't ask again"));
1506 dialog.setWindowTitle(tr("There are still open tabs"));
1507 dialog.setIcon(QMessageBox::Warning);
1508
1509 if (dialog.exec() != QMessageBox::Yes) {
1510 event->ignore();
1511 return;
1512 }
1513
1514 if (dialog.isChecked()) {
1515 settings.setValue(QSL("Browser-Tabs-Settings/AskOnClosing"), false);
1516 }
1517 }
1518
1519 emit aboutToClose();
1520
1521 saveSettings();
1522 mApp->closedWindowsManager()->saveWindow(this);
1523
1524 #ifndef Q_OS_MACOS
1525 if (mApp->windowCount() == 1)
1526 mApp->quitApplication();
1527 #endif
1528
1529 event->accept();
1530 }
1531
closeWindow()1532 void BrowserWindow::closeWindow()
1533 {
1534 #ifdef Q_OS_MACOS
1535 close();
1536 return;
1537 #endif
1538
1539 if (mApp->windowCount() > 1) {
1540 close();
1541 }
1542 }
1543
saveSettings()1544 void BrowserWindow::saveSettings()
1545 {
1546 if (mApp->isPrivate()) {
1547 return;
1548 }
1549
1550 Settings settings;
1551 settings.beginGroup(QSL("Browser-View-Settings"));
1552 settings.setValue(QSL("WindowGeometry"), saveGeometry());
1553
1554 const auto state = saveUiState();
1555 for (auto it = state.constBegin(); it != state.constEnd(); ++it) {
1556 settings.setValue(it.key(), it.value());
1557 }
1558
1559 settings.endGroup();
1560 }
1561
closeTab()1562 void BrowserWindow::closeTab()
1563 {
1564 // Don't close pinned tabs with keyboard shortcuts (Ctrl+W, Ctrl+F4)
1565 if (weView() && !weView()->webTab()->isPinned()) {
1566 m_tabWidget->requestCloseTab();
1567 }
1568 }
1569
1570 #ifdef QZ_WS_X11
getCurrentVirtualDesktop() const1571 int BrowserWindow::getCurrentVirtualDesktop() const
1572 {
1573 if (QGuiApplication::platformName() != QL1S("xcb"))
1574 return 0;
1575
1576 xcb_intern_atom_cookie_t intern_atom;
1577 xcb_intern_atom_reply_t *atom_reply = 0;
1578 xcb_atom_t atom;
1579 xcb_get_property_cookie_t cookie;
1580 xcb_get_property_reply_t *reply = 0;
1581 uint32_t value;
1582
1583 intern_atom = xcb_intern_atom(QX11Info::connection(), false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP");
1584 atom_reply = xcb_intern_atom_reply(QX11Info::connection(), intern_atom, 0);
1585
1586 if (!atom_reply)
1587 goto error;
1588
1589 atom = atom_reply->atom;
1590
1591 cookie = xcb_get_property(QX11Info::connection(), false, winId(), atom, XCB_ATOM_CARDINAL, 0, 1);
1592 reply = xcb_get_property_reply(QX11Info::connection(), cookie, 0);
1593
1594 if (!reply || reply->type != XCB_ATOM_CARDINAL || reply->value_len != 1 || reply->format != sizeof(uint32_t) * 8)
1595 goto error;
1596
1597 value = *reinterpret_cast<uint32_t*>(xcb_get_property_value(reply));
1598
1599 free(reply);
1600 free(atom_reply);
1601 return value;
1602
1603 error:
1604 free(reply);
1605 free(atom_reply);
1606 return 0;
1607 }
1608
moveToVirtualDesktop(int desktopId)1609 void BrowserWindow::moveToVirtualDesktop(int desktopId)
1610 {
1611 if (QGuiApplication::platformName() != QL1S("xcb"))
1612 return;
1613
1614 // Don't move when window is already visible or it is first app window
1615 if (desktopId < 0 || isVisible() || m_windowType == Qz::BW_FirstAppWindow)
1616 return;
1617
1618 xcb_intern_atom_cookie_t intern_atom;
1619 xcb_intern_atom_reply_t *atom_reply = 0;
1620 xcb_atom_t atom;
1621
1622 intern_atom = xcb_intern_atom(QX11Info::connection(), false, qstrlen("_NET_WM_DESKTOP"), "_NET_WM_DESKTOP");
1623 atom_reply = xcb_intern_atom_reply(QX11Info::connection(), intern_atom, 0);
1624
1625 if (!atom_reply)
1626 goto error;
1627
1628 atom = atom_reply->atom;
1629
1630 xcb_change_property(QX11Info::connection(), XCB_PROP_MODE_REPLACE, winId(), atom,
1631 XCB_ATOM_CARDINAL, 32, 1, (const void*) &desktopId);
1632
1633 error:
1634 free(atom_reply);
1635 }
1636 #endif
1637