2022-07-05 23:18:21 +01:00
|
|
|
/*
|
2024-10-04 13:19:50 +02:00
|
|
|
* Copyright (c) 2022-2023, Andreas Kling <andreas@ladybird.org>
|
2022-07-05 23:18:21 +01:00
|
|
|
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
|
2022-07-14 06:08:30 +02:00
|
|
|
* Copyright (c) 2022, Filiph Sandström <filiph.sandstrom@filfatstudios.com>
|
2023-01-12 14:39:53 +00:00
|
|
|
* Copyright (c) 2023, Linus Groh <linusg@serenityos.org>
|
2025-07-23 11:29:45 +01:00
|
|
|
* Copyright (c) 2024-2025, Sam Atkins <sam@ladybird.org>
|
2022-07-05 23:18:21 +01:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2022-09-13 12:18:32 -04:00
|
|
|
#include <AK/TypeCasts.h>
|
2024-07-30 14:01:05 -04:00
|
|
|
#include <LibWebView/Application.h>
|
2024-11-09 12:50:33 -05:00
|
|
|
#include <UI/Qt/Application.h>
|
|
|
|
#include <UI/Qt/BrowserWindow.h>
|
|
|
|
#include <UI/Qt/Icon.h>
|
2025-09-01 08:20:14 -04:00
|
|
|
#include <UI/Qt/Menu.h>
|
2024-11-09 12:50:33 -05:00
|
|
|
#include <UI/Qt/Settings.h>
|
|
|
|
#include <UI/Qt/StringUtils.h>
|
|
|
|
#include <UI/Qt/TabBar.h>
|
|
|
|
#include <UI/Qt/WebContentView.h>
|
|
|
|
|
2022-07-05 21:10:50 +02:00
|
|
|
#include <QAction>
|
2022-09-19 10:48:02 +02:00
|
|
|
#include <QActionGroup>
|
2023-01-11 20:09:52 +01:00
|
|
|
#include <QGuiApplication>
|
2022-09-26 17:57:44 +03:00
|
|
|
#include <QInputDialog>
|
2025-03-15 10:10:25 -04:00
|
|
|
#include <QMessageBox>
|
2025-09-01 08:20:14 -04:00
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QScreen>
|
2023-09-20 11:32:37 +02:00
|
|
|
#include <QShortcut>
|
2025-03-15 10:10:25 -04:00
|
|
|
#include <QStatusBar>
|
2025-09-01 08:20:14 -04:00
|
|
|
#include <QWheelEvent>
|
2023-12-13 19:10:05 +01:00
|
|
|
#include <QWindow>
|
2022-07-03 21:26:51 +02:00
|
|
|
|
2023-08-02 11:52:59 -06:00
|
|
|
namespace Ladybird {
|
2022-07-08 14:14:40 +02:00
|
|
|
|
2023-05-27 16:25:22 +02:00
|
|
|
static QIcon const& app_icon()
|
|
|
|
{
|
|
|
|
static QIcon icon;
|
|
|
|
if (icon.isNull()) {
|
|
|
|
QPixmap pixmap;
|
|
|
|
pixmap.load(":/Icons/ladybird.png");
|
|
|
|
icon = QIcon(pixmap);
|
|
|
|
}
|
|
|
|
return icon;
|
|
|
|
}
|
|
|
|
|
2024-05-07 23:39:25 +01:00
|
|
|
class HamburgerMenu : public QMenu {
|
|
|
|
public:
|
|
|
|
using QMenu::QMenu;
|
|
|
|
virtual ~HamburgerMenu() override = default;
|
|
|
|
|
|
|
|
virtual void showEvent(QShowEvent*) override
|
|
|
|
{
|
|
|
|
if (!isVisible())
|
|
|
|
return;
|
2025-01-21 09:12:05 -05:00
|
|
|
auto* browser_window = as<BrowserWindow>(parentWidget());
|
2024-05-07 23:39:25 +01:00
|
|
|
if (!browser_window)
|
|
|
|
return;
|
|
|
|
auto* current_tab = browser_window->current_tab();
|
|
|
|
if (!current_tab)
|
|
|
|
return;
|
|
|
|
// Ensure the hamburger menu placed within the browser window.
|
|
|
|
auto* hamburger_button = current_tab->hamburger_button();
|
|
|
|
auto button_top_right = hamburger_button->mapToGlobal(hamburger_button->rect().bottomRight());
|
|
|
|
move(button_top_right - QPoint(rect().width(), 0));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2024-09-05 18:19:51 -04:00
|
|
|
BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, IsPopupWindow is_popup_window, Tab* parent_tab, Optional<u64> page_index)
|
2024-04-02 21:38:01 -04:00
|
|
|
: m_tabs_container(new TabWidget(this))
|
2024-07-14 16:24:48 -04:00
|
|
|
, m_new_tab_button_toolbar(new QToolBar("New Tab", m_tabs_container))
|
2024-07-27 11:38:39 +01:00
|
|
|
, m_is_popup_window(is_popup_window)
|
2022-07-03 21:26:51 +02:00
|
|
|
{
|
2025-07-02 12:42:53 -04:00
|
|
|
auto const& browser_options = WebView::Application::browser_options();
|
|
|
|
|
2023-05-27 16:25:22 +02:00
|
|
|
setWindowIcon(app_icon());
|
2022-07-12 11:41:11 +02:00
|
|
|
|
2023-12-13 19:10:05 +01:00
|
|
|
// Listen for DPI changes
|
|
|
|
m_device_pixel_ratio = devicePixelRatio();
|
|
|
|
m_current_screen = screen();
|
2025-07-25 16:43:27 +01:00
|
|
|
m_refresh_rate = m_current_screen->refreshRate();
|
|
|
|
|
2024-01-26 23:14:41 -05:00
|
|
|
if (QT_VERSION < QT_VERSION_CHECK(6, 6, 0) || QGuiApplication::platformName() != "wayland") {
|
|
|
|
setAttribute(Qt::WA_NativeWindow);
|
|
|
|
setAttribute(Qt::WA_DontCreateNativeAncestors);
|
2023-12-13 19:10:05 +01:00
|
|
|
QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &BrowserWindow::device_pixel_ratio_changed);
|
2025-07-25 16:43:27 +01:00
|
|
|
QObject::connect(m_current_screen, &QScreen::refreshRateChanged, this, &BrowserWindow::refresh_rate_changed);
|
2024-01-26 23:14:41 -05:00
|
|
|
QObject::connect(windowHandle(), &QWindow::screenChanged, this, [this](QScreen* screen) {
|
|
|
|
if (m_device_pixel_ratio != devicePixelRatio())
|
|
|
|
device_pixel_ratio_changed(devicePixelRatio());
|
|
|
|
|
2025-07-25 16:43:27 +01:00
|
|
|
if (m_refresh_rate != screen->refreshRate())
|
|
|
|
refresh_rate_changed(screen->refreshRate());
|
|
|
|
|
|
|
|
// Listen for logicalDotsPerInchChanged and refreshRateChanged signals on new screen
|
2024-01-26 23:14:41 -05:00
|
|
|
QObject::disconnect(m_current_screen, &QScreen::logicalDotsPerInchChanged, nullptr, nullptr);
|
2025-07-25 16:43:27 +01:00
|
|
|
QObject::disconnect(m_current_screen, &QScreen::refreshRateChanged, nullptr, nullptr);
|
2024-01-26 23:14:41 -05:00
|
|
|
m_current_screen = screen;
|
|
|
|
QObject::connect(m_current_screen, &QScreen::logicalDotsPerInchChanged, this, &BrowserWindow::device_pixel_ratio_changed);
|
2025-07-25 16:43:27 +01:00
|
|
|
QObject::connect(m_current_screen, &QScreen::refreshRateChanged, this, &BrowserWindow::refresh_rate_changed);
|
2024-01-26 23:14:41 -05:00
|
|
|
});
|
|
|
|
}
|
2023-12-13 19:10:05 +01:00
|
|
|
|
2024-05-07 23:39:25 +01:00
|
|
|
m_hamburger_menu = new HamburgerMenu(this);
|
2024-05-05 16:11:51 +01:00
|
|
|
|
|
|
|
if (!Settings::the()->show_menubar())
|
|
|
|
menuBar()->hide();
|
|
|
|
|
|
|
|
QObject::connect(Settings::the(), &Settings::show_menubar_changed, this, [this](bool show_menubar) {
|
|
|
|
menuBar()->setVisible(show_menubar);
|
|
|
|
});
|
|
|
|
|
|
|
|
auto* file_menu = menuBar()->addMenu("&File");
|
2022-07-07 02:55:21 +02:00
|
|
|
|
2024-04-05 07:21:48 -04:00
|
|
|
m_new_tab_action = new QAction("New &Tab", this);
|
|
|
|
m_new_tab_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::AddTab));
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addAction(m_new_tab_action);
|
|
|
|
file_menu->addAction(m_new_tab_action);
|
2022-07-07 02:55:21 +02:00
|
|
|
|
2024-04-26 18:53:55 -06:00
|
|
|
m_new_window_action = new QAction("New &Window", this);
|
|
|
|
m_new_window_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::New));
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addAction(m_new_window_action);
|
|
|
|
file_menu->addAction(m_new_window_action);
|
2024-04-26 18:53:55 -06:00
|
|
|
|
2023-05-25 03:26:42 +02:00
|
|
|
auto* close_current_tab_action = new QAction("&Close Current Tab", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
close_current_tab_action->setIcon(load_icon_from_uri("resource://icons/16x16/close-tab.png"sv));
|
2023-01-12 19:39:07 +01:00
|
|
|
close_current_tab_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Close));
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addAction(close_current_tab_action);
|
|
|
|
file_menu->addAction(close_current_tab_action);
|
2022-07-19 06:16:46 -04:00
|
|
|
|
2023-05-25 23:47:12 +02:00
|
|
|
auto* open_file_action = new QAction("&Open File...", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
open_file_action->setIcon(load_icon_from_uri("resource://icons/16x16/filetype-folder-open.png"sv));
|
2023-05-25 23:47:12 +02:00
|
|
|
open_file_action->setShortcut(QKeySequence(QKeySequence::StandardKey::Open));
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addAction(open_file_action);
|
|
|
|
file_menu->addAction(open_file_action);
|
2023-05-25 23:47:12 +02:00
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addSeparator();
|
2023-05-25 22:35:27 +02:00
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
auto* edit_menu = m_hamburger_menu->addMenu("&Edit");
|
|
|
|
menuBar()->addMenu(edit_menu);
|
2023-01-11 20:09:52 +01:00
|
|
|
|
2025-09-01 08:20:14 -04:00
|
|
|
edit_menu->addAction(create_application_action(*this, Application::the().copy_selection_action()));
|
|
|
|
edit_menu->addAction(create_application_action(*this, Application::the().paste_action()));
|
|
|
|
edit_menu->addAction(create_application_action(*this, Application::the().select_all_action()));
|
2023-05-25 22:35:27 +02:00
|
|
|
edit_menu->addSeparator();
|
|
|
|
|
2024-05-29 20:12:21 +01:00
|
|
|
m_find_in_page_action = new QAction("&Find in Page...", this);
|
|
|
|
m_find_in_page_action->setIcon(load_icon_from_uri("resource://icons/16x16/find.png"sv));
|
|
|
|
m_find_in_page_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Find));
|
|
|
|
|
2024-06-13 21:09:49 +01:00
|
|
|
auto find_previous_shortcuts = QKeySequence::keyBindings(QKeySequence::StandardKey::FindPrevious);
|
|
|
|
for (auto const& shortcut : find_previous_shortcuts)
|
|
|
|
new QShortcut(shortcut, this, [this] {
|
|
|
|
if (m_current_tab)
|
|
|
|
m_current_tab->find_previous();
|
|
|
|
});
|
|
|
|
|
|
|
|
auto find_next_shortcuts = QKeySequence::keyBindings(QKeySequence::StandardKey::FindNext);
|
|
|
|
for (auto const& shortcut : find_next_shortcuts)
|
|
|
|
new QShortcut(shortcut, this, [this] {
|
|
|
|
if (m_current_tab)
|
|
|
|
m_current_tab->find_next();
|
|
|
|
});
|
|
|
|
|
2024-05-29 20:12:21 +01:00
|
|
|
edit_menu->addAction(m_find_in_page_action);
|
|
|
|
QObject::connect(m_find_in_page_action, &QAction::triggered, this, &BrowserWindow::show_find_in_page);
|
|
|
|
|
|
|
|
edit_menu->addSeparator();
|
|
|
|
|
2023-05-25 03:23:33 +02:00
|
|
|
auto* settings_action = new QAction("&Settings", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
settings_action->setIcon(load_icon_from_uri("resource://icons/16x16/settings.png"sv));
|
2023-05-25 03:23:33 +02:00
|
|
|
settings_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Preferences));
|
|
|
|
edit_menu->addAction(settings_action);
|
2025-03-21 09:51:00 -04:00
|
|
|
QObject::connect(settings_action, &QAction::triggered, this, [this] {
|
|
|
|
new_tab_from_url(URL::URL::about("settings"_string), Web::HTML::ActivateTab::Yes);
|
|
|
|
});
|
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
auto* view_menu = m_hamburger_menu->addMenu("&View");
|
|
|
|
menuBar()->addMenu(view_menu);
|
2022-09-12 09:22:43 +02:00
|
|
|
|
2022-10-01 12:46:24 -06:00
|
|
|
auto* open_next_tab_action = new QAction("Open &Next Tab", this);
|
2022-09-12 09:22:43 +02:00
|
|
|
open_next_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
|
|
|
|
view_menu->addAction(open_next_tab_action);
|
|
|
|
QObject::connect(open_next_tab_action, &QAction::triggered, this, &BrowserWindow::open_next_tab);
|
|
|
|
|
2022-10-01 12:46:24 -06:00
|
|
|
auto* open_previous_tab_action = new QAction("Open &Previous Tab", this);
|
2022-09-12 09:22:43 +02:00
|
|
|
open_previous_tab_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
|
|
|
|
view_menu->addAction(open_previous_tab_action);
|
|
|
|
QObject::connect(open_previous_tab_action, &QAction::triggered, this, &BrowserWindow::open_previous_tab);
|
|
|
|
|
2022-09-19 10:48:02 +02:00
|
|
|
view_menu->addSeparator();
|
|
|
|
|
2023-03-26 18:56:17 +01:00
|
|
|
m_zoom_menu = view_menu->addMenu("&Zoom");
|
2023-01-12 14:39:53 +00:00
|
|
|
|
|
|
|
auto* zoom_in_action = new QAction("Zoom &In", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
zoom_in_action->setIcon(load_icon_from_uri("resource://icons/16x16/zoom-in.png"sv));
|
2023-01-12 19:52:24 +01:00
|
|
|
auto zoom_in_shortcuts = QKeySequence::keyBindings(QKeySequence::StandardKey::ZoomIn);
|
2024-06-09 22:52:19 +01:00
|
|
|
auto secondary_zoom_shortcut = QKeySequence(Qt::CTRL | Qt::Key_Equal);
|
|
|
|
if (!zoom_in_shortcuts.contains(secondary_zoom_shortcut))
|
|
|
|
zoom_in_shortcuts.append(AK::move(secondary_zoom_shortcut));
|
|
|
|
|
2023-01-12 19:52:24 +01:00
|
|
|
zoom_in_action->setShortcuts(zoom_in_shortcuts);
|
2023-03-26 18:56:17 +01:00
|
|
|
m_zoom_menu->addAction(zoom_in_action);
|
2023-01-12 14:39:53 +00:00
|
|
|
QObject::connect(zoom_in_action, &QAction::triggered, this, &BrowserWindow::zoom_in);
|
|
|
|
|
|
|
|
auto* zoom_out_action = new QAction("Zoom &Out", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
zoom_out_action->setIcon(load_icon_from_uri("resource://icons/16x16/zoom-out.png"sv));
|
2023-01-12 19:39:07 +01:00
|
|
|
zoom_out_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::ZoomOut));
|
2023-03-26 18:56:17 +01:00
|
|
|
m_zoom_menu->addAction(zoom_out_action);
|
2023-01-12 14:39:53 +00:00
|
|
|
QObject::connect(zoom_out_action, &QAction::triggered, this, &BrowserWindow::zoom_out);
|
|
|
|
|
|
|
|
auto* reset_zoom_action = new QAction("&Reset Zoom", this);
|
2023-11-05 07:45:43 -05:00
|
|
|
reset_zoom_action->setIcon(load_icon_from_uri("resource://icons/16x16/zoom-reset.png"sv));
|
2023-01-12 14:39:53 +00:00
|
|
|
reset_zoom_action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
|
2023-03-26 18:56:17 +01:00
|
|
|
m_zoom_menu->addAction(reset_zoom_action);
|
2023-01-12 14:39:53 +00:00
|
|
|
QObject::connect(reset_zoom_action, &QAction::triggered, this, &BrowserWindow::reset_zoom);
|
|
|
|
|
|
|
|
view_menu->addSeparator();
|
|
|
|
|
2025-09-03 11:23:09 -04:00
|
|
|
view_menu->addMenu(create_application_menu(*view_menu, Application::the().color_scheme_menu()));
|
|
|
|
view_menu->addMenu(create_application_menu(*view_menu, Application::the().contrast_menu()));
|
|
|
|
view_menu->addMenu(create_application_menu(*view_menu, Application::the().motion_menu()));
|
|
|
|
view_menu->addSeparator();
|
2024-06-13 16:15:59 +02:00
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
auto* show_menubar = new QAction("Show &Menubar", this);
|
|
|
|
show_menubar->setCheckable(true);
|
|
|
|
show_menubar->setChecked(Settings::the()->show_menubar());
|
|
|
|
view_menu->addAction(show_menubar);
|
|
|
|
QObject::connect(show_menubar, &QAction::triggered, this, [](bool checked) {
|
|
|
|
Settings::the()->set_show_menubar(checked);
|
|
|
|
});
|
|
|
|
|
|
|
|
auto* inspect_menu = m_hamburger_menu->addMenu("&Inspect");
|
|
|
|
menuBar()->addMenu(inspect_menu);
|
2022-07-09 17:46:11 +02:00
|
|
|
|
2025-09-01 08:20:14 -04:00
|
|
|
edit_menu->addAction(create_application_action(*this, Application::the().view_source_action()));
|
2022-07-09 17:46:11 +02:00
|
|
|
|
2025-03-15 10:10:25 -04:00
|
|
|
m_enable_devtools_action = new QAction("Enable &DevTools", this);
|
|
|
|
m_enable_devtools_action->setIcon(load_icon_from_uri("resource://icons/browser/dom-tree.png"sv));
|
|
|
|
m_enable_devtools_action->setShortcuts({
|
|
|
|
QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_I),
|
|
|
|
QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_C),
|
|
|
|
QKeySequence(Qt::Key_F12),
|
|
|
|
});
|
|
|
|
inspect_menu->addAction(m_enable_devtools_action);
|
|
|
|
QObject::connect(m_enable_devtools_action, &QAction::triggered, this, [this] {
|
|
|
|
if (auto result = WebView::Application::the().toggle_devtools_enabled(); result.is_error()) {
|
|
|
|
auto error_message = MUST(String::formatted("Unable to start DevTools: {}", result.error()));
|
|
|
|
QMessageBox::warning(this, "Ladybird", qstring_from_ak_string(error_message));
|
|
|
|
} else {
|
|
|
|
switch (result.value()) {
|
|
|
|
case WebView::Application::DevtoolsState::Disabled:
|
|
|
|
devtools_disabled();
|
|
|
|
break;
|
|
|
|
case WebView::Application::DevtoolsState::Enabled:
|
|
|
|
devtools_enabled();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-03-26 11:38:12 -06:00
|
|
|
auto* task_manager_action = new QAction("Open Task &Manager", this);
|
|
|
|
task_manager_action->setIcon(load_icon_from_uri("resource://icons/16x16/app-system-monitor.png"sv));
|
|
|
|
task_manager_action->setShortcuts({ QKeySequence("Ctrl+Shift+M") });
|
|
|
|
inspect_menu->addAction(task_manager_action);
|
2025-03-16 11:16:58 -04:00
|
|
|
QObject::connect(task_manager_action, &QAction::triggered, this, [this]() {
|
|
|
|
new_tab_from_url(URL::URL::about("processes"_string), Web::HTML::ActivateTab::Yes);
|
2024-03-26 11:38:12 -06:00
|
|
|
});
|
|
|
|
|
2025-09-03 09:00:52 -04:00
|
|
|
auto* debug_menu = create_application_menu(*m_hamburger_menu, Application::the().debug_menu());
|
|
|
|
m_hamburger_menu->addMenu(debug_menu);
|
2024-05-06 18:13:54 +01:00
|
|
|
menuBar()->addMenu(debug_menu);
|
2022-07-08 14:14:40 +02:00
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
auto* help_menu = m_hamburger_menu->addMenu("&Help");
|
|
|
|
menuBar()->addMenu(help_menu);
|
2024-05-05 15:40:36 +01:00
|
|
|
|
|
|
|
auto* about_action = new QAction("&About Ladybird", this);
|
|
|
|
help_menu->addAction(about_action);
|
2024-01-12 19:41:26 +01:00
|
|
|
QObject::connect(about_action, &QAction::triggered, this, [this] {
|
2025-02-22 21:51:15 +13:00
|
|
|
new_tab_from_url(URL::about_version(), Web::HTML::ActivateTab::Yes);
|
2024-01-12 19:41:26 +01:00
|
|
|
});
|
2024-05-05 15:40:36 +01:00
|
|
|
|
2024-05-05 16:11:51 +01:00
|
|
|
m_hamburger_menu->addSeparator();
|
|
|
|
file_menu->addSeparator();
|
|
|
|
|
|
|
|
auto* quit_action = new QAction("&Quit", this);
|
|
|
|
quit_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Quit));
|
|
|
|
m_hamburger_menu->addAction(quit_action);
|
|
|
|
file_menu->addAction(quit_action);
|
|
|
|
QObject::connect(quit_action, &QAction::triggered, this, &QMainWindow::close);
|
|
|
|
|
2024-04-05 07:21:48 -04:00
|
|
|
QObject::connect(m_new_tab_action, &QAction::triggered, this, [this] {
|
2025-03-20 12:59:44 -04:00
|
|
|
auto& tab = new_tab_from_url(WebView::Application::settings().new_tab_page_url(), Web::HTML::ActivateTab::Yes);
|
2024-06-20 19:11:19 +01:00
|
|
|
tab.set_url_is_hidden(true);
|
|
|
|
tab.focus_location_editor();
|
2023-01-08 11:21:55 +01:00
|
|
|
});
|
2024-09-05 18:19:51 -04:00
|
|
|
QObject::connect(m_new_window_action, &QAction::triggered, this, [] {
|
2025-06-10 14:50:23 -04:00
|
|
|
(void)Application::the().new_window({});
|
2024-04-26 18:53:55 -06:00
|
|
|
});
|
2023-05-25 23:47:12 +02:00
|
|
|
QObject::connect(open_file_action, &QAction::triggered, this, &BrowserWindow::open_file);
|
2022-07-05 23:18:21 +01:00
|
|
|
QObject::connect(m_tabs_container, &QTabWidget::currentChanged, [this](int index) {
|
2025-01-21 09:12:05 -05:00
|
|
|
auto* tab = as<Tab>(m_tabs_container->widget(index));
|
2024-04-27 14:33:09 +01:00
|
|
|
if (tab)
|
|
|
|
setWindowTitle(QString("%1 - Ladybird").arg(tab->title()));
|
|
|
|
|
|
|
|
set_current_tab(tab);
|
2022-07-05 23:18:21 +01:00
|
|
|
});
|
2022-07-06 14:36:49 +01:00
|
|
|
QObject::connect(m_tabs_container, &QTabWidget::tabCloseRequested, this, &BrowserWindow::close_tab);
|
2022-07-19 06:16:46 -04:00
|
|
|
QObject::connect(close_current_tab_action, &QAction::triggered, this, &BrowserWindow::close_current_tab);
|
2022-07-03 21:26:51 +02:00
|
|
|
|
2023-09-20 11:32:37 +02:00
|
|
|
for (int i = 0; i <= 7; ++i) {
|
|
|
|
new QShortcut(QKeySequence(Qt::CTRL | static_cast<Qt::Key>(Qt::Key_1 + i)), this, [this, i] {
|
|
|
|
if (m_tabs_container->count() <= 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_tabs_container->setCurrentIndex(min(i, m_tabs_container->count() - 1));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_9), this, [this] {
|
|
|
|
if (m_tabs_container->count() <= 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_tabs_container->setCurrentIndex(m_tabs_container->count() - 1);
|
|
|
|
});
|
|
|
|
|
2024-05-28 13:27:57 -06:00
|
|
|
if (parent_tab) {
|
|
|
|
new_child_tab(Web::HTML::ActivateTab::Yes, *parent_tab, AK::move(page_index));
|
|
|
|
} else {
|
2024-07-30 14:01:05 -04:00
|
|
|
for (size_t i = 0; i < initial_urls.size(); ++i) {
|
|
|
|
new_tab_from_url(initial_urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
|
2024-05-28 13:27:57 -06:00
|
|
|
}
|
2023-08-08 15:59:55 -04:00
|
|
|
}
|
2022-07-05 23:18:21 +01:00
|
|
|
|
2024-07-14 16:24:48 -04:00
|
|
|
m_new_tab_button_toolbar->addAction(m_new_tab_action);
|
|
|
|
m_new_tab_button_toolbar->setMovable(false);
|
|
|
|
m_new_tab_button_toolbar->setStyleSheet("QToolBar { background: transparent; }");
|
|
|
|
m_new_tab_button_toolbar->setIconSize(QSize(16, 16));
|
2024-07-26 11:38:26 +01:00
|
|
|
m_tabs_container->setCornerWidget(m_new_tab_button_toolbar, Qt::TopRightCorner);
|
2024-07-14 16:24:48 -04:00
|
|
|
|
2022-07-05 23:18:21 +01:00
|
|
|
setCentralWidget(m_tabs_container);
|
2023-05-15 11:49:44 -04:00
|
|
|
setContextMenuPolicy(Qt::PreventContextMenu);
|
2025-07-02 12:42:53 -04:00
|
|
|
|
|
|
|
if (browser_options.devtools_port.has_value())
|
|
|
|
devtools_enabled();
|
2023-05-08 21:15:35 +01:00
|
|
|
}
|
|
|
|
|
2025-03-15 10:10:25 -04:00
|
|
|
void BrowserWindow::devtools_disabled()
|
|
|
|
{
|
|
|
|
m_enable_devtools_action->setText("Enable &DevTools");
|
|
|
|
setStatusBar(nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::devtools_enabled()
|
|
|
|
{
|
2025-03-20 12:30:27 +01:00
|
|
|
auto* disable_button = new QPushButton("Disable", this);
|
2025-03-15 10:10:25 -04:00
|
|
|
|
|
|
|
connect(disable_button, &QPushButton::clicked, this, [this]() {
|
|
|
|
MUST(WebView::Application::the().toggle_devtools_enabled());
|
|
|
|
devtools_disabled();
|
|
|
|
});
|
|
|
|
|
|
|
|
m_enable_devtools_action->setText("Disable &DevTools");
|
|
|
|
statusBar()->addPermanentWidget(disable_button);
|
|
|
|
|
2025-03-15 16:56:52 -04:00
|
|
|
auto message = MUST(String::formatted("DevTools is enabled on port {}", WebView::Application::browser_options().devtools_port));
|
2025-03-15 10:10:25 -04:00
|
|
|
statusBar()->showMessage(qstring_from_ak_string(message));
|
|
|
|
}
|
|
|
|
|
2023-03-26 18:56:17 +01:00
|
|
|
void BrowserWindow::set_current_tab(Tab* tab)
|
|
|
|
{
|
|
|
|
m_current_tab = tab;
|
2025-09-01 08:20:14 -04:00
|
|
|
if (tab)
|
2023-03-29 00:25:42 +01:00
|
|
|
update_displayed_zoom_level();
|
2023-03-26 18:56:17 +01:00
|
|
|
}
|
|
|
|
|
2024-03-18 16:22:27 +13:00
|
|
|
Tab& BrowserWindow::new_tab_from_url(URL::URL const& url, Web::HTML::ActivateTab activate_tab)
|
2023-08-28 16:14:34 -04:00
|
|
|
{
|
|
|
|
auto& tab = create_new_tab(activate_tab);
|
|
|
|
tab.navigate(url);
|
|
|
|
return tab;
|
|
|
|
}
|
|
|
|
|
2024-01-30 18:52:59 -07:00
|
|
|
Tab& BrowserWindow::new_tab_from_content(StringView html, Web::HTML::ActivateTab activate_tab)
|
2023-08-28 16:14:34 -04:00
|
|
|
{
|
|
|
|
auto& tab = create_new_tab(activate_tab);
|
2023-09-17 17:12:17 +02:00
|
|
|
tab.load_html(html);
|
2023-08-28 16:14:34 -04:00
|
|
|
return tab;
|
|
|
|
}
|
|
|
|
|
2024-05-28 13:27:57 -06:00
|
|
|
Tab& BrowserWindow::new_child_tab(Web::HTML::ActivateTab activate_tab, Tab& parent, Optional<u64> page_index)
|
2024-01-30 20:05:00 -07:00
|
|
|
{
|
2024-05-28 13:27:57 -06:00
|
|
|
return create_new_tab(activate_tab, parent, page_index);
|
2024-01-30 20:05:00 -07:00
|
|
|
}
|
|
|
|
|
2024-05-28 13:27:57 -06:00
|
|
|
Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab, Tab& parent, Optional<u64> page_index)
|
2024-01-30 20:05:00 -07:00
|
|
|
{
|
|
|
|
if (!page_index.has_value())
|
|
|
|
return create_new_tab(activate_tab);
|
|
|
|
|
2024-07-30 14:01:05 -04:00
|
|
|
auto* tab = new Tab(this, parent.view().client(), page_index.value());
|
2024-01-30 20:05:00 -07:00
|
|
|
|
2024-05-28 13:27:57 -06:00
|
|
|
// FIXME: Merge with other overload
|
|
|
|
if (m_current_tab == nullptr) {
|
|
|
|
set_current_tab(tab);
|
|
|
|
}
|
2024-01-30 20:05:00 -07:00
|
|
|
|
|
|
|
m_tabs_container->addTab(tab, "New Tab");
|
2024-06-20 19:11:19 +01:00
|
|
|
if (activate_tab == Web::HTML::ActivateTab::Yes)
|
2024-01-30 20:05:00 -07:00
|
|
|
m_tabs_container->setCurrentWidget(tab);
|
2024-06-20 19:11:19 +01:00
|
|
|
|
2024-01-30 20:05:00 -07:00
|
|
|
initialize_tab(tab);
|
|
|
|
return *tab;
|
|
|
|
}
|
|
|
|
|
2023-08-28 16:14:34 -04:00
|
|
|
Tab& BrowserWindow::create_new_tab(Web::HTML::ActivateTab activate_tab)
|
2022-07-05 23:18:21 +01:00
|
|
|
{
|
2024-07-30 14:01:05 -04:00
|
|
|
auto* tab = new Tab(this);
|
2022-07-03 21:26:51 +02:00
|
|
|
|
2022-07-05 23:18:21 +01:00
|
|
|
if (m_current_tab == nullptr) {
|
2023-12-04 09:39:22 -05:00
|
|
|
set_current_tab(tab);
|
2022-07-05 23:18:21 +01:00
|
|
|
}
|
2022-07-03 21:26:51 +02:00
|
|
|
|
2023-12-04 09:39:22 -05:00
|
|
|
m_tabs_container->addTab(tab, "New Tab");
|
2024-06-20 19:11:19 +01:00
|
|
|
if (activate_tab == Web::HTML::ActivateTab::Yes)
|
2023-12-04 09:39:22 -05:00
|
|
|
m_tabs_container->setCurrentWidget(tab);
|
2024-06-20 19:11:19 +01:00
|
|
|
|
2024-01-30 20:05:00 -07:00
|
|
|
initialize_tab(tab);
|
|
|
|
|
|
|
|
return *tab;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::initialize_tab(Tab* tab)
|
|
|
|
{
|
2023-12-04 09:39:22 -05:00
|
|
|
QObject::connect(tab, &Tab::title_changed, this, &BrowserWindow::tab_title_changed);
|
|
|
|
QObject::connect(tab, &Tab::favicon_changed, this, &BrowserWindow::tab_favicon_changed);
|
2024-03-28 11:16:10 -04:00
|
|
|
QObject::connect(tab, &Tab::audio_play_state_changed, this, &BrowserWindow::tab_audio_play_state_changed);
|
2022-07-12 11:41:11 +02:00
|
|
|
|
2023-12-04 09:39:22 -05:00
|
|
|
QObject::connect(&tab->view(), &WebContentView::urls_dropped, this, [this](auto& urls) {
|
2023-01-07 17:40:04 +01:00
|
|
|
VERIFY(urls.size());
|
2024-01-30 19:15:55 -07:00
|
|
|
m_current_tab->navigate(ak_url_from_qurl(urls[0]));
|
2023-01-07 17:40:04 +01:00
|
|
|
|
|
|
|
for (qsizetype i = 1; i < urls.size(); ++i)
|
2024-01-30 19:15:55 -07:00
|
|
|
new_tab_from_url(ak_url_from_qurl(urls[i]), Web::HTML::ActivateTab::No);
|
2023-01-07 17:40:04 +01:00
|
|
|
});
|
|
|
|
|
2024-01-30 20:05:00 -07:00
|
|
|
tab->view().on_new_web_view = [this, tab](auto activate_tab, Web::HTML::WebViewHints hints, Optional<u64> page_index) {
|
2024-05-28 13:27:57 -06:00
|
|
|
if (hints.popup) {
|
2025-06-10 14:50:23 -04:00
|
|
|
auto& window = Application::the().new_window({}, IsPopupWindow::Yes, tab, AK::move(page_index));
|
2024-05-28 13:27:57 -06:00
|
|
|
window.set_window_rect(hints.screen_x, hints.screen_y, hints.width, hints.height);
|
|
|
|
return window.current_tab()->view().handle();
|
|
|
|
}
|
|
|
|
auto& new_tab = new_child_tab(activate_tab, *tab, page_index);
|
2024-01-30 20:05:00 -07:00
|
|
|
return new_tab.view().handle();
|
2023-03-14 17:19:28 +03:00
|
|
|
};
|
|
|
|
|
2023-12-04 09:39:22 -05:00
|
|
|
tab->view().on_tab_open_request = [this](auto url, auto activate_tab) {
|
2024-01-30 19:15:55 -07:00
|
|
|
auto& tab = new_tab_from_url(url, activate_tab);
|
2023-03-22 21:24:15 -03:00
|
|
|
return tab.view().handle();
|
|
|
|
};
|
|
|
|
|
2023-12-04 09:39:22 -05:00
|
|
|
tab->view().on_link_click = [this](auto url, auto target, unsigned modifiers) {
|
2023-03-22 21:24:15 -03:00
|
|
|
// TODO: maybe activate tabs according to some configuration, this is just normal current browser behavior
|
2024-06-06 13:29:08 -06:00
|
|
|
if (modifiers == Web::UIEvents::Mod_Ctrl) {
|
2023-03-22 21:24:15 -03:00
|
|
|
m_current_tab->view().on_tab_open_request(url, Web::HTML::ActivateTab::No);
|
|
|
|
} else if (target == "_blank") {
|
|
|
|
m_current_tab->view().on_tab_open_request(url, Web::HTML::ActivateTab::Yes);
|
2023-05-15 12:27:10 -04:00
|
|
|
} else {
|
|
|
|
m_current_tab->view().load(url);
|
2023-03-22 21:24:15 -03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-12-04 09:39:22 -05:00
|
|
|
tab->view().on_link_middle_click = [this](auto url, auto target, unsigned modifiers) {
|
2024-06-06 13:29:08 -06:00
|
|
|
m_current_tab->view().on_link_click(url, target, Web::UIEvents::Mod_Ctrl);
|
2023-03-22 21:24:15 -03:00
|
|
|
(void)modifiers;
|
|
|
|
};
|
|
|
|
|
2024-03-28 11:11:02 -04:00
|
|
|
m_tabs_container->setTabIcon(m_tabs_container->indexOf(tab), tab->favicon());
|
2024-04-02 21:35:52 -04:00
|
|
|
create_close_button_for_tab(tab);
|
2022-07-03 21:26:51 +02:00
|
|
|
}
|
|
|
|
|
2023-03-20 19:52:00 -04:00
|
|
|
void BrowserWindow::activate_tab(int index)
|
|
|
|
{
|
|
|
|
m_tabs_container->setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
|
2022-07-06 14:36:49 +01:00
|
|
|
void BrowserWindow::close_tab(int index)
|
|
|
|
{
|
|
|
|
auto* tab = m_tabs_container->widget(index);
|
|
|
|
m_tabs_container->removeTab(index);
|
2023-12-04 09:39:22 -05:00
|
|
|
tab->deleteLater();
|
2024-04-05 07:36:12 -04:00
|
|
|
|
|
|
|
if (m_tabs_container->count() == 0)
|
|
|
|
close();
|
2022-07-06 14:36:49 +01:00
|
|
|
}
|
|
|
|
|
2024-04-28 15:07:23 +01:00
|
|
|
void BrowserWindow::move_tab(int old_index, int new_index)
|
|
|
|
{
|
|
|
|
m_tabs_container->tabBar()->moveTab(old_index, new_index);
|
|
|
|
}
|
|
|
|
|
2023-05-25 23:47:12 +02:00
|
|
|
void BrowserWindow::open_file()
|
|
|
|
{
|
|
|
|
m_current_tab->open_file();
|
|
|
|
}
|
|
|
|
|
2022-07-19 06:16:46 -04:00
|
|
|
void BrowserWindow::close_current_tab()
|
|
|
|
{
|
2023-08-08 18:42:18 -04:00
|
|
|
close_tab(m_tabs_container->currentIndex());
|
2022-07-19 06:16:46 -04:00
|
|
|
}
|
|
|
|
|
2022-07-05 23:18:21 +01:00
|
|
|
int BrowserWindow::tab_index(Tab* tab)
|
2022-07-03 21:26:51 +02:00
|
|
|
{
|
2022-07-05 23:18:21 +01:00
|
|
|
return m_tabs_container->indexOf(tab);
|
2022-07-03 21:26:51 +02:00
|
|
|
}
|
2022-07-04 02:11:58 +02:00
|
|
|
|
2023-12-13 19:10:05 +01:00
|
|
|
void BrowserWindow::device_pixel_ratio_changed(qreal dpi)
|
|
|
|
{
|
|
|
|
m_device_pixel_ratio = dpi;
|
|
|
|
for_each_tab([this](auto& tab) {
|
|
|
|
tab.view().set_device_pixel_ratio(m_device_pixel_ratio);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2025-07-25 16:43:27 +01:00
|
|
|
void BrowserWindow::refresh_rate_changed(qreal refresh_rate)
|
|
|
|
{
|
|
|
|
m_refresh_rate = refresh_rate;
|
|
|
|
for_each_tab([this](auto& tab) {
|
|
|
|
tab.view().set_maximum_frames_per_second(m_refresh_rate);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-07-05 23:18:21 +01:00
|
|
|
void BrowserWindow::tab_title_changed(int index, QString const& title)
|
2022-07-04 02:11:58 +02:00
|
|
|
{
|
2024-08-12 13:37:11 +01:00
|
|
|
// NOTE: Qt uses ampersands for shortcut keys in tab titles, so we need to escape them.
|
|
|
|
QString title_escaped = title;
|
|
|
|
title_escaped.replace("&", "&&");
|
|
|
|
|
|
|
|
m_tabs_container->setTabText(index, title_escaped);
|
2024-04-02 21:45:09 -04:00
|
|
|
m_tabs_container->setTabToolTip(index, title);
|
|
|
|
|
2023-06-07 16:37:30 -04:00
|
|
|
if (m_tabs_container->currentIndex() == index)
|
|
|
|
setWindowTitle(QString("%1 - Ladybird").arg(title));
|
2022-07-04 02:11:58 +02:00
|
|
|
}
|
2022-07-05 05:53:11 +01:00
|
|
|
|
2023-05-29 19:05:40 +10:00
|
|
|
void BrowserWindow::tab_favicon_changed(int index, QIcon const& icon)
|
2022-07-05 05:53:11 +01:00
|
|
|
{
|
2022-07-05 23:18:21 +01:00
|
|
|
m_tabs_container->setTabIcon(index, icon);
|
2022-07-05 05:53:11 +01:00
|
|
|
}
|
2022-09-12 09:22:43 +02:00
|
|
|
|
2024-04-02 21:35:52 -04:00
|
|
|
void BrowserWindow::create_close_button_for_tab(Tab* tab)
|
|
|
|
{
|
|
|
|
auto index = m_tabs_container->indexOf(tab);
|
|
|
|
m_tabs_container->setTabIcon(index, tab->favicon());
|
|
|
|
|
|
|
|
auto* button = new TabBarButton(create_tvg_icon_with_theme_colors("close", palette()));
|
|
|
|
auto position = audio_button_position_for_tab(index) == QTabBar::LeftSide ? QTabBar::RightSide : QTabBar::LeftSide;
|
|
|
|
|
|
|
|
connect(button, &QPushButton::clicked, this, [this, tab]() {
|
|
|
|
auto index = m_tabs_container->indexOf(tab);
|
|
|
|
close_tab(index);
|
|
|
|
});
|
|
|
|
|
|
|
|
m_tabs_container->tabBar()->setTabButton(index, position, button);
|
|
|
|
}
|
|
|
|
|
2024-03-28 11:16:10 -04:00
|
|
|
void BrowserWindow::tab_audio_play_state_changed(int index, Web::HTML::AudioPlayState play_state)
|
|
|
|
{
|
2025-01-21 09:12:05 -05:00
|
|
|
auto* tab = as<Tab>(m_tabs_container->widget(index));
|
2024-03-30 18:47:50 -04:00
|
|
|
auto position = audio_button_position_for_tab(index);
|
2024-03-30 18:36:26 -04:00
|
|
|
|
2024-03-28 11:16:10 -04:00
|
|
|
switch (play_state) {
|
|
|
|
case Web::HTML::AudioPlayState::Paused:
|
2024-03-30 18:36:26 -04:00
|
|
|
if (tab->view().page_mute_state() == Web::HTML::MuteState::Unmuted)
|
2024-03-30 18:47:50 -04:00
|
|
|
m_tabs_container->tabBar()->setTabButton(index, position, nullptr);
|
2024-03-28 11:16:10 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case Web::HTML::AudioPlayState::Playing:
|
2024-04-02 21:24:17 -04:00
|
|
|
auto* button = new TabBarButton(icon_for_page_mute_state(*tab));
|
2024-03-30 18:36:26 -04:00
|
|
|
button->setToolTip(tool_tip_for_page_mute_state(*tab));
|
2024-04-02 12:52:03 -04:00
|
|
|
button->setObjectName("LadybirdAudioState");
|
2024-03-28 11:16:10 -04:00
|
|
|
|
2024-03-30 18:47:50 -04:00
|
|
|
connect(button, &QPushButton::clicked, this, [this, tab, position]() {
|
2024-03-30 18:36:26 -04:00
|
|
|
tab->view().toggle_page_mute_state();
|
|
|
|
auto index = tab_index(tab);
|
2024-03-30 09:48:33 -04:00
|
|
|
|
2024-03-30 18:36:26 -04:00
|
|
|
switch (tab->view().audio_play_state()) {
|
2024-03-30 09:48:33 -04:00
|
|
|
case Web::HTML::AudioPlayState::Paused:
|
2024-03-30 18:47:50 -04:00
|
|
|
m_tabs_container->tabBar()->setTabButton(index, position, nullptr);
|
2024-03-30 09:48:33 -04:00
|
|
|
break;
|
|
|
|
case Web::HTML::AudioPlayState::Playing:
|
2024-03-30 18:47:50 -04:00
|
|
|
auto* button = m_tabs_container->tabBar()->tabButton(index, position);
|
2025-01-21 09:12:05 -05:00
|
|
|
as<TabBarButton>(button)->setIcon(icon_for_page_mute_state(*tab));
|
2024-03-30 18:36:26 -04:00
|
|
|
button->setToolTip(tool_tip_for_page_mute_state(*tab));
|
2024-03-30 09:48:33 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
2024-03-28 11:16:10 -04:00
|
|
|
|
2024-03-30 18:47:50 -04:00
|
|
|
m_tabs_container->tabBar()->setTabButton(index, position, button);
|
2024-03-28 11:16:10 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-30 18:36:26 -04:00
|
|
|
QIcon BrowserWindow::icon_for_page_mute_state(Tab& tab) const
|
2024-03-30 09:48:33 -04:00
|
|
|
{
|
2024-03-30 18:36:26 -04:00
|
|
|
switch (tab.view().page_mute_state()) {
|
2024-03-30 09:48:33 -04:00
|
|
|
case Web::HTML::MuteState::Muted:
|
|
|
|
return style()->standardIcon(QStyle::SP_MediaVolumeMuted);
|
|
|
|
case Web::HTML::MuteState::Unmuted:
|
|
|
|
return style()->standardIcon(QStyle::SP_MediaVolume);
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2024-03-30 18:36:26 -04:00
|
|
|
QString BrowserWindow::tool_tip_for_page_mute_state(Tab& tab) const
|
2024-03-30 11:10:11 -04:00
|
|
|
{
|
2024-03-30 18:36:26 -04:00
|
|
|
switch (tab.view().page_mute_state()) {
|
2024-03-30 11:10:11 -04:00
|
|
|
case Web::HTML::MuteState::Muted:
|
|
|
|
return "Unmute tab";
|
|
|
|
case Web::HTML::MuteState::Unmuted:
|
|
|
|
return "Mute tab";
|
|
|
|
}
|
|
|
|
|
|
|
|
VERIFY_NOT_REACHED();
|
|
|
|
}
|
|
|
|
|
2024-03-30 18:47:50 -04:00
|
|
|
QTabBar::ButtonPosition BrowserWindow::audio_button_position_for_tab(int tab_index) const
|
|
|
|
{
|
2024-04-02 12:52:03 -04:00
|
|
|
if (auto* button = m_tabs_container->tabBar()->tabButton(tab_index, QTabBar::LeftSide)) {
|
|
|
|
if (button->objectName() != "LadybirdAudioState")
|
|
|
|
return QTabBar::RightSide;
|
|
|
|
}
|
|
|
|
|
2024-03-30 18:47:50 -04:00
|
|
|
return QTabBar::LeftSide;
|
|
|
|
}
|
|
|
|
|
2022-09-12 09:22:43 +02:00
|
|
|
void BrowserWindow::open_next_tab()
|
|
|
|
{
|
|
|
|
if (m_tabs_container->count() <= 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto next_index = m_tabs_container->currentIndex() + 1;
|
|
|
|
if (next_index >= m_tabs_container->count())
|
|
|
|
next_index = 0;
|
|
|
|
m_tabs_container->setCurrentIndex(next_index);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::open_previous_tab()
|
|
|
|
{
|
|
|
|
if (m_tabs_container->count() <= 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto next_index = m_tabs_container->currentIndex() - 1;
|
|
|
|
if (next_index < 0)
|
|
|
|
next_index = m_tabs_container->count() - 1;
|
|
|
|
m_tabs_container->setCurrentIndex(next_index);
|
|
|
|
}
|
2022-09-19 10:48:02 +02:00
|
|
|
|
2023-01-12 14:39:53 +00:00
|
|
|
void BrowserWindow::zoom_in()
|
|
|
|
{
|
2023-03-26 18:56:17 +01:00
|
|
|
if (!m_current_tab)
|
|
|
|
return;
|
|
|
|
m_current_tab->view().zoom_in();
|
2023-03-29 00:25:42 +01:00
|
|
|
update_displayed_zoom_level();
|
2023-01-12 14:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::zoom_out()
|
|
|
|
{
|
2023-03-26 18:56:17 +01:00
|
|
|
if (!m_current_tab)
|
|
|
|
return;
|
|
|
|
m_current_tab->view().zoom_out();
|
2023-03-29 00:25:42 +01:00
|
|
|
update_displayed_zoom_level();
|
2023-01-12 14:39:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::reset_zoom()
|
|
|
|
{
|
2023-03-26 18:56:17 +01:00
|
|
|
if (!m_current_tab)
|
|
|
|
return;
|
|
|
|
m_current_tab->view().reset_zoom();
|
2023-03-29 00:25:42 +01:00
|
|
|
update_displayed_zoom_level();
|
2023-01-12 14:39:53 +00:00
|
|
|
}
|
2023-01-11 20:09:52 +01:00
|
|
|
|
2023-08-04 13:37:52 +02:00
|
|
|
void BrowserWindow::update_zoom_menu()
|
|
|
|
{
|
|
|
|
VERIFY(m_zoom_menu);
|
|
|
|
auto zoom_level_text = MUST(String::formatted("&Zoom ({}%)", round_to<int>(m_current_tab->view().zoom_level() * 100)));
|
|
|
|
m_zoom_menu->setTitle(qstring_from_ak_string(zoom_level_text));
|
|
|
|
}
|
|
|
|
|
2024-05-29 20:12:21 +01:00
|
|
|
void BrowserWindow::show_find_in_page()
|
|
|
|
{
|
|
|
|
if (!m_current_tab)
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_current_tab->show_find_in_page();
|
|
|
|
}
|
|
|
|
|
2023-03-29 00:25:42 +01:00
|
|
|
void BrowserWindow::update_displayed_zoom_level()
|
2023-03-26 18:56:17 +01:00
|
|
|
{
|
2023-08-04 13:37:52 +02:00
|
|
|
VERIFY(m_current_tab);
|
|
|
|
update_zoom_menu();
|
2023-03-29 00:25:42 +01:00
|
|
|
m_current_tab->update_reset_zoom_button();
|
2023-03-26 18:56:17 +01:00
|
|
|
}
|
|
|
|
|
2024-05-28 13:27:57 -06:00
|
|
|
void BrowserWindow::set_window_rect(Optional<Web::DevicePixels> x, Optional<Web::DevicePixels> y, Optional<Web::DevicePixels> width, Optional<Web::DevicePixels> height)
|
|
|
|
{
|
|
|
|
x = x.value_or(0);
|
|
|
|
y = y.value_or(0);
|
|
|
|
if (!width.has_value() || width.value() == 0)
|
|
|
|
width = 800;
|
|
|
|
if (!height.has_value() || height.value() == 0)
|
|
|
|
height = 600;
|
|
|
|
|
|
|
|
setGeometry(x.value().value(), y.value().value(), width.value().value(), height.value().value());
|
|
|
|
}
|
|
|
|
|
2024-01-26 23:14:41 -05:00
|
|
|
bool BrowserWindow::event(QEvent* event)
|
|
|
|
{
|
|
|
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0)
|
|
|
|
if (event->type() == QEvent::DevicePixelRatioChange) {
|
|
|
|
if (m_device_pixel_ratio != devicePixelRatio())
|
|
|
|
device_pixel_ratio_changed(devicePixelRatio());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-04-26 18:53:55 -06:00
|
|
|
if (event->type() == QEvent::WindowActivate)
|
2025-06-10 14:50:23 -04:00
|
|
|
Application::the().set_active_window(*this);
|
2024-04-26 18:53:55 -06:00
|
|
|
|
2024-01-26 23:14:41 -05:00
|
|
|
return QMainWindow::event(event);
|
|
|
|
}
|
|
|
|
|
2023-03-08 23:57:24 +03:00
|
|
|
void BrowserWindow::resizeEvent(QResizeEvent* event)
|
|
|
|
{
|
|
|
|
QWidget::resizeEvent(event);
|
2023-12-04 09:39:22 -05:00
|
|
|
|
|
|
|
for_each_tab([&](auto& tab) {
|
2024-10-28 15:13:57 -04:00
|
|
|
tab.view().set_window_size({ width(), height() });
|
2023-12-04 09:39:22 -05:00
|
|
|
});
|
2023-03-08 23:57:24 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void BrowserWindow::moveEvent(QMoveEvent* event)
|
|
|
|
{
|
|
|
|
QWidget::moveEvent(event);
|
2023-12-04 09:39:22 -05:00
|
|
|
|
|
|
|
for_each_tab([&](auto& tab) {
|
2024-10-28 15:13:57 -04:00
|
|
|
tab.view().set_window_position({ x(), y() });
|
2023-12-04 09:39:22 -05:00
|
|
|
});
|
2023-03-08 23:57:24 +03:00
|
|
|
}
|
|
|
|
|
2023-06-30 17:33:04 -05:00
|
|
|
void BrowserWindow::wheelEvent(QWheelEvent* event)
|
|
|
|
{
|
|
|
|
if ((event->modifiers() & Qt::ControlModifier) != 0) {
|
|
|
|
if (event->angleDelta().y() > 0)
|
|
|
|
zoom_in();
|
|
|
|
else if (event->angleDelta().y() < 0)
|
|
|
|
zoom_out();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-05 03:26:20 +01:00
|
|
|
bool BrowserWindow::eventFilter(QObject* obj, QEvent* event)
|
|
|
|
{
|
|
|
|
if (event->type() == QEvent::MouseButtonRelease) {
|
|
|
|
auto const* const mouse_event = static_cast<QMouseEvent*>(event);
|
|
|
|
if (mouse_event->button() == Qt::MouseButton::MiddleButton) {
|
|
|
|
if (obj == m_tabs_container) {
|
|
|
|
auto const tab_index = m_tabs_container->tabBar()->tabAt(mouse_event->pos());
|
2024-06-28 23:06:58 +01:00
|
|
|
if (tab_index != -1) {
|
|
|
|
close_tab(tab_index);
|
|
|
|
return true;
|
|
|
|
}
|
2023-02-05 03:26:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return QMainWindow::eventFilter(obj, event);
|
|
|
|
}
|
2023-08-02 11:52:59 -06:00
|
|
|
|
2023-08-09 12:23:32 +02:00
|
|
|
void BrowserWindow::closeEvent(QCloseEvent* event)
|
|
|
|
{
|
2024-07-27 11:38:39 +01:00
|
|
|
if (m_is_popup_window == IsPopupWindow::No) {
|
|
|
|
Settings::the()->set_last_position(pos());
|
|
|
|
Settings::the()->set_last_size(size());
|
|
|
|
Settings::the()->set_is_maximized(isMaximized());
|
|
|
|
}
|
2023-08-09 12:23:32 +02:00
|
|
|
|
2024-04-26 18:53:55 -06:00
|
|
|
QObject::deleteLater();
|
2023-08-09 12:23:32 +02:00
|
|
|
|
2024-04-26 18:53:55 -06:00
|
|
|
QMainWindow::closeEvent(event);
|
2024-03-26 11:38:12 -06:00
|
|
|
}
|
|
|
|
|
2023-08-02 11:52:59 -06:00
|
|
|
}
|