2022-07-05 19:18:21 -03:00
|
|
|
/*
|
2024-10-04 08:19:50 -03:00
|
|
|
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
|
2022-07-05 19:18:21 -03:00
|
|
|
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
|
2024-04-28 11:07:23 -03:00
|
|
|
* Copyright (c) 2024, Jamie Mansfield <jmansfield@cadixdev.org>
|
2022-07-05 19:18:21 -03:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
|
*/
|
|
|
|
|
|
2026-05-26 13:03:07 -03:00
|
|
|
#include <LibCore/EventLoop.h>
|
2025-09-01 09:20:14 -03:00
|
|
|
#include <LibURL/URL.h>
|
2024-02-25 15:09:26 -03:00
|
|
|
#include <LibWeb/HTML/SelectedFile.h>
|
2025-03-20 13:59:44 -03:00
|
|
|
#include <LibWebView/Application.h>
|
2026-05-20 13:37:49 -03:00
|
|
|
#include <LibWebView/Utilities.h>
|
2026-05-24 05:02:05 -03:00
|
|
|
#include <LibWebView/WebContentClient.h>
|
2024-11-09 14:50:33 -03:00
|
|
|
#include <UI/Qt/BrowserWindow.h>
|
2026-05-25 16:21:50 -03:00
|
|
|
#include <UI/Qt/ChromeStyle.h>
|
2024-11-09 14:50:33 -03:00
|
|
|
#include <UI/Qt/Icon.h>
|
2025-09-01 09:20:14 -03:00
|
|
|
#include <UI/Qt/Menu.h>
|
2024-11-09 14:50:33 -03:00
|
|
|
#include <UI/Qt/Settings.h>
|
|
|
|
|
#include <UI/Qt/StringUtils.h>
|
|
|
|
|
|
2023-09-04 10:46:20 -03:00
|
|
|
#include <QColorDialog>
|
2023-05-25 18:47:12 -03:00
|
|
|
#include <QFileDialog>
|
2022-09-09 09:23:36 -03:00
|
|
|
#include <QFont>
|
|
|
|
|
#include <QFontMetrics>
|
2026-05-25 16:22:32 -03:00
|
|
|
#include <QHBoxLayout>
|
2023-05-15 14:43:58 -03:00
|
|
|
#include <QImage>
|
2023-05-17 15:23:34 -03:00
|
|
|
#include <QInputDialog>
|
2023-05-15 12:49:44 -03:00
|
|
|
#include <QMenu>
|
2023-05-16 08:56:12 -03:00
|
|
|
#include <QMessageBox>
|
2023-11-10 15:44:12 -03:00
|
|
|
#include <QMimeData>
|
2024-03-14 20:19:51 -03:00
|
|
|
#include <QMimeDatabase>
|
2022-09-09 09:23:36 -03:00
|
|
|
#include <QResizeEvent>
|
2026-05-19 16:29:55 -03:00
|
|
|
#include <QTimer>
|
2022-07-05 19:18:21 -03:00
|
|
|
|
2023-08-02 14:52:59 -03:00
|
|
|
namespace Ladybird {
|
|
|
|
|
|
2026-03-16 14:16:32 -03:00
|
|
|
class HamburgerButton final : public QToolButton {
|
|
|
|
|
public:
|
|
|
|
|
using QToolButton::QToolButton;
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
virtual void mousePressEvent(QMouseEvent* event) override
|
|
|
|
|
{
|
|
|
|
|
if (event->button() == Qt::LeftButton)
|
|
|
|
|
show_menu();
|
|
|
|
|
else
|
|
|
|
|
QToolButton::mousePressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
virtual void keyPressEvent(QKeyEvent* event) override
|
|
|
|
|
{
|
|
|
|
|
if (first_is_one_of(event->key(), Qt::Key_Select, Qt::Key_Space))
|
|
|
|
|
show_menu();
|
|
|
|
|
else
|
|
|
|
|
QToolButton::keyPressEvent(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void show_menu()
|
|
|
|
|
{
|
|
|
|
|
auto* menu = this->menu();
|
|
|
|
|
VERIFY(menu);
|
|
|
|
|
|
|
|
|
|
auto bottom_right = mapToGlobal(rect().bottomRight());
|
|
|
|
|
auto menu_width = menu->sizeHint().width();
|
|
|
|
|
|
|
|
|
|
menu->popup(QPoint { bottom_right.x() - menu_width, bottom_right.y() });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-29 07:53:53 -03:00
|
|
|
static QIcon default_favicon()
|
|
|
|
|
{
|
2024-07-07 12:30:22 -03:00
|
|
|
static QIcon icon = load_icon_from_uri("resource://icons/48x48/app-browser.png"sv);
|
2024-03-29 07:53:53 -03:00
|
|
|
return icon;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 16:22:32 -03:00
|
|
|
static QToolButton* create_toolbar_button(QWidget& parent, QAction& action)
|
|
|
|
|
{
|
|
|
|
|
auto* button = new QToolButton(&parent);
|
|
|
|
|
button->setDefaultAction(&action);
|
|
|
|
|
button->setAutoRaise(true);
|
|
|
|
|
button->setFocusPolicy(Qt::NoFocus);
|
|
|
|
|
button->setIconSize({ 20, 20 });
|
2026-05-31 12:58:57 -03:00
|
|
|
button->setFixedSize(36, 36);
|
2026-05-25 16:22:32 -03:00
|
|
|
return button;
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-30 15:01:05 -03:00
|
|
|
Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client, size_t page_index)
|
2022-10-01 15:46:24 -03:00
|
|
|
: QWidget(window)
|
|
|
|
|
, m_window(window)
|
2022-07-05 19:18:21 -03:00
|
|
|
{
|
2026-05-27 10:09:15 -03:00
|
|
|
auto* tab_layout = new QBoxLayout(QBoxLayout::Direction::TopToBottom, this);
|
|
|
|
|
tab_layout->setSpacing(0);
|
|
|
|
|
tab_layout->setContentsMargins(0, 0, 0, 0);
|
2022-07-05 19:18:21 -03:00
|
|
|
|
2025-07-25 12:43:27 -03:00
|
|
|
auto view_initial_state = WebContentViewInitialState {
|
|
|
|
|
.maximum_frames_per_second = window->refresh_rate(),
|
2026-05-28 14:04:22 -03:00
|
|
|
.display_id = window->display_id(),
|
2025-07-25 12:43:27 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
m_view = new WebContentView(this, parent_client, page_index, AK::move(view_initial_state));
|
2024-05-29 16:12:21 -03:00
|
|
|
m_find_in_page = new FindInPageWidget(this, m_view);
|
|
|
|
|
m_find_in_page->setVisible(false);
|
2026-05-27 10:12:53 -03:00
|
|
|
|
|
|
|
|
m_toolbar_container = new QWidget(this);
|
|
|
|
|
m_toolbar_container->setObjectName("LadybirdToolbarContainer");
|
2026-05-28 13:46:35 -03:00
|
|
|
m_toolbar_container->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
2026-05-27 10:12:53 -03:00
|
|
|
|
2026-05-25 16:22:32 -03:00
|
|
|
m_toolbar = new QWidget(this);
|
2026-05-25 16:21:50 -03:00
|
|
|
m_toolbar->setObjectName("LadybirdNavigationToolbar");
|
2026-05-31 12:58:57 -03:00
|
|
|
m_toolbar->setFixedHeight(42);
|
2026-05-25 16:22:32 -03:00
|
|
|
m_toolbar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
|
|
|
|
|
|
2026-05-27 10:12:53 -03:00
|
|
|
auto* toolbar_container_layout = new QVBoxLayout(m_toolbar_container);
|
|
|
|
|
toolbar_container_layout->setSpacing(0);
|
|
|
|
|
toolbar_container_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
|
|
2026-05-25 16:22:32 -03:00
|
|
|
auto* toolbar_layout = new QHBoxLayout(m_toolbar);
|
2026-05-26 09:17:10 -03:00
|
|
|
toolbar_layout->setSpacing(6);
|
2026-05-31 12:58:57 -03:00
|
|
|
toolbar_layout->setContentsMargins(12, 2, 12, 2);
|
2026-05-25 16:22:32 -03:00
|
|
|
|
2023-01-18 11:12:13 -03:00
|
|
|
m_location_edit = new LocationEdit(this);
|
2026-03-22 20:25:10 -03:00
|
|
|
m_bookmarks_bar = new BookmarksBar(this);
|
2026-05-19 16:29:55 -03:00
|
|
|
m_loading_animation_timer = new QTimer(this);
|
|
|
|
|
m_loading_animation_timer->setInterval(80);
|
2022-07-05 19:18:21 -03:00
|
|
|
|
2024-08-23 21:18:57 -03:00
|
|
|
m_hover_label = new HyperlinkLabel(this);
|
2022-09-09 10:19:18 -03:00
|
|
|
m_hover_label->hide();
|
2026-05-25 22:05:11 -03:00
|
|
|
m_hover_label->setContentsMargins(4, 2, 4, 2);
|
2022-09-09 09:23:36 -03:00
|
|
|
m_hover_label->setAutoFillBackground(true);
|
|
|
|
|
|
2024-08-23 21:18:57 -03:00
|
|
|
QObject::connect(m_hover_label, &HyperlinkLabel::mouse_entered, [this] {
|
|
|
|
|
update_hover_label();
|
|
|
|
|
});
|
2026-05-19 16:29:55 -03:00
|
|
|
QObject::connect(m_loading_animation_timer, &QTimer::timeout, this, [this] {
|
|
|
|
|
m_loading_animation_frame = (m_loading_animation_frame + 1) % 12;
|
|
|
|
|
update_tab_icon();
|
|
|
|
|
});
|
2024-08-23 21:18:57 -03:00
|
|
|
|
2023-07-19 13:07:50 -03:00
|
|
|
auto* focus_location_editor_action = new QAction("Edit Location", this);
|
2025-08-06 20:06:31 -03:00
|
|
|
focus_location_editor_action->setShortcuts({ QKeySequence("Ctrl+L"), QKeySequence("Alt+D") });
|
2022-09-12 04:12:04 -03:00
|
|
|
addAction(focus_location_editor_action);
|
2022-07-06 21:56:09 -03:00
|
|
|
|
2026-05-27 10:12:53 -03:00
|
|
|
toolbar_container_layout->addWidget(m_toolbar);
|
|
|
|
|
toolbar_container_layout->addWidget(m_bookmarks_bar);
|
|
|
|
|
tab_layout->addWidget(m_toolbar_container);
|
2026-05-27 10:09:15 -03:00
|
|
|
tab_layout->addWidget(m_view);
|
|
|
|
|
tab_layout->addWidget(m_find_in_page);
|
2022-07-05 19:18:21 -03:00
|
|
|
|
2026-03-16 14:16:32 -03:00
|
|
|
m_hamburger_button = new HamburgerButton(m_toolbar);
|
2024-05-05 12:11:51 -03:00
|
|
|
m_hamburger_button->setText("Show &Menu");
|
|
|
|
|
m_hamburger_button->setToolTip("Show Menu");
|
2026-05-31 12:59:17 -03:00
|
|
|
m_hamburger_button->setIcon(create_chrome_icon(ChromeIcon::Menu, palette()));
|
2026-05-25 16:22:32 -03:00
|
|
|
m_hamburger_button->setIconSize({ 20, 20 });
|
2026-05-31 12:58:57 -03:00
|
|
|
m_hamburger_button->setFixedSize(36, 36);
|
2026-05-25 16:22:32 -03:00
|
|
|
m_hamburger_button->setAutoRaise(true);
|
|
|
|
|
m_hamburger_button->setFocusPolicy(Qt::NoFocus);
|
2024-05-05 12:11:51 -03:00
|
|
|
m_hamburger_button->setPopupMode(QToolButton::InstantPopup);
|
|
|
|
|
m_hamburger_button->setMenu(&m_window->hamburger_menu());
|
2026-05-25 16:22:07 -03:00
|
|
|
connect_hamburger_menu();
|
2026-03-16 14:16:32 -03:00
|
|
|
|
2025-09-01 09:20:14 -03:00
|
|
|
m_navigate_back_action = create_application_action(*this, view().navigate_back_action());
|
|
|
|
|
m_navigate_forward_action = create_application_action(*this, view().navigate_forward_action());
|
|
|
|
|
m_reload_action = create_application_action(*this, WebView::Application::the().reload_action());
|
|
|
|
|
|
2023-07-29 15:46:47 -03:00
|
|
|
recreate_toolbar_icons();
|
2023-05-05 10:38:46 -03:00
|
|
|
|
2024-03-29 07:53:53 -03:00
|
|
|
m_favicon = default_favicon();
|
2024-03-28 12:11:02 -03:00
|
|
|
|
2025-09-01 09:20:14 -03:00
|
|
|
m_page_context_menu = create_context_menu(*this, view(), view().page_context_menu());
|
|
|
|
|
m_link_context_menu = create_context_menu(*this, view(), view().link_context_menu());
|
|
|
|
|
m_image_context_menu = create_context_menu(*this, view(), view().image_context_menu());
|
|
|
|
|
m_media_context_menu = create_context_menu(*this, view(), view().media_context_menu());
|
|
|
|
|
|
2026-05-25 16:22:32 -03:00
|
|
|
toolbar_layout->addWidget(create_toolbar_button(*m_toolbar, *m_navigate_back_action));
|
|
|
|
|
toolbar_layout->addWidget(create_toolbar_button(*m_toolbar, *m_navigate_forward_action));
|
|
|
|
|
toolbar_layout->addWidget(create_toolbar_button(*m_toolbar, *m_reload_action));
|
|
|
|
|
m_location_edit->set_trailing_action(create_application_action(*m_location_edit, view().toggle_bookmark_action()));
|
|
|
|
|
toolbar_layout->addWidget(m_location_edit, 1);
|
|
|
|
|
toolbar_layout->addWidget(m_hamburger_button);
|
2025-09-11 08:45:57 -03:00
|
|
|
|
2026-05-25 16:21:50 -03:00
|
|
|
update_chrome_style();
|
2023-07-30 19:25:32 -03:00
|
|
|
|
2026-05-25 16:22:32 -03:00
|
|
|
m_hamburger_button->setVisible(!Settings::the()->show_menubar());
|
2024-05-05 12:11:51 -03:00
|
|
|
|
|
|
|
|
QObject::connect(Settings::the(), &Settings::show_menubar_changed, this, [this](bool show_menubar) {
|
2026-05-25 16:22:32 -03:00
|
|
|
m_hamburger_button->setVisible(!show_menubar);
|
2024-05-05 12:11:51 -03:00
|
|
|
});
|
|
|
|
|
|
2023-05-17 13:37:31 -03:00
|
|
|
view().on_activate_tab = [this] {
|
2023-03-20 20:52:00 -03:00
|
|
|
m_window->activate_tab(tab_index());
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
2023-03-20 20:52:00 -03:00
|
|
|
|
2023-05-17 13:37:31 -03:00
|
|
|
view().on_close = [this] {
|
2025-11-07 13:50:49 -03:00
|
|
|
m_window->definitely_close_tab(tab_index());
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
2023-03-07 00:13:08 -03:00
|
|
|
|
2023-05-17 13:37:31 -03:00
|
|
|
view().on_link_hover = [this](auto const& url) {
|
2023-12-16 11:19:34 -03:00
|
|
|
m_hover_label->setText(qstring_from_ak_string(url.to_byte_string()));
|
2022-09-09 09:23:36 -03:00
|
|
|
update_hover_label();
|
|
|
|
|
m_hover_label->show();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_link_unhover = [this]() {
|
2022-09-09 09:23:36 -03:00
|
|
|
m_hover_label->hide();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
2022-07-05 19:18:21 -03:00
|
|
|
|
2025-08-29 09:02:52 -03:00
|
|
|
view().on_load_start = [this](URL::URL const& url, bool) {
|
2024-03-28 12:11:02 -03:00
|
|
|
auto url_serialized = qstring_from_ak_string(url.serialize());
|
|
|
|
|
|
|
|
|
|
m_title = url_serialized;
|
2026-05-24 05:02:05 -03:00
|
|
|
update_tab_title();
|
2024-03-28 12:11:02 -03:00
|
|
|
|
2024-03-29 07:53:53 -03:00
|
|
|
m_favicon = default_favicon();
|
2026-05-19 16:29:55 -03:00
|
|
|
set_loading(true);
|
2024-03-29 07:53:53 -03:00
|
|
|
|
2026-05-19 08:40:00 -03:00
|
|
|
m_location_edit->set_favicon({});
|
|
|
|
|
m_location_edit->set_loading(true);
|
2024-06-10 06:33:35 -03:00
|
|
|
m_location_edit->set_url(url);
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
2023-05-17 12:54:36 -03:00
|
|
|
|
2026-05-19 08:40:00 -03:00
|
|
|
view().on_load_finish = [this](auto const&) {
|
2026-05-19 16:29:55 -03:00
|
|
|
set_loading(false);
|
2026-05-19 08:40:00 -03:00
|
|
|
m_location_edit->set_loading(false);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_web_content_crashed = [this] {
|
2026-05-19 16:29:55 -03:00
|
|
|
set_loading(false);
|
2026-05-19 08:40:00 -03:00
|
|
|
m_location_edit->set_loading(false);
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-13 19:05:47 -03:00
|
|
|
view().on_url_change = [this](auto const& url) {
|
2024-06-10 06:33:35 -03:00
|
|
|
m_location_edit->set_url(url);
|
2024-03-29 07:55:09 -03:00
|
|
|
};
|
|
|
|
|
|
2022-07-05 19:18:21 -03:00
|
|
|
QObject::connect(m_location_edit, &QLineEdit::returnPressed, this, &Tab::location_edit_return_pressed);
|
2023-05-17 13:37:31 -03:00
|
|
|
|
|
|
|
|
view().on_title_change = [this](auto const& title) {
|
2025-07-28 17:51:01 -03:00
|
|
|
m_title = qstring_from_utf16_string(title);
|
2026-05-24 05:02:05 -03:00
|
|
|
update_tab_title();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_favicon_change = [this](auto const& bitmap) {
|
|
|
|
|
auto qimage = QImage(bitmap.scanline_u8(0), bitmap.width(), bitmap.height(), QImage::Format_ARGB32);
|
|
|
|
|
if (qimage.isNull())
|
|
|
|
|
return;
|
|
|
|
|
auto qpixmap = QPixmap::fromImage(qimage);
|
|
|
|
|
if (qpixmap.isNull())
|
|
|
|
|
return;
|
2024-03-28 12:11:02 -03:00
|
|
|
|
|
|
|
|
m_favicon = qpixmap;
|
2026-05-19 16:29:55 -03:00
|
|
|
update_tab_icon();
|
2026-05-19 08:40:00 -03:00
|
|
|
m_location_edit->set_favicon(m_favicon);
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
2023-05-17 15:23:34 -03:00
|
|
|
view().on_request_alert = [this](auto const& message) {
|
|
|
|
|
m_dialog = new QMessageBox(QMessageBox::Icon::Warning, "Ladybird", qstring_from_ak_string(message), QMessageBox::StandardButton::Ok, &view());
|
|
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
QObject::connect(m_dialog, &QDialog::finished, this, [this]() {
|
|
|
|
|
view().alert_closed();
|
|
|
|
|
m_dialog = nullptr;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_dialog->open();
|
2023-05-17 15:23:34 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_request_confirm = [this](auto const& message) {
|
|
|
|
|
m_dialog = new QMessageBox(QMessageBox::Icon::Question, "Ladybird", qstring_from_ak_string(message), QMessageBox::StandardButton::Ok | QMessageBox::StandardButton::Cancel, &view());
|
|
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
QObject::connect(m_dialog, &QDialog::finished, this, [this](auto result) {
|
|
|
|
|
view().confirm_closed(result == QMessageBox::StandardButton::Ok || result == QDialog::Accepted);
|
|
|
|
|
m_dialog = nullptr;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_dialog->open();
|
2023-05-17 15:23:34 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_request_prompt = [this](auto const& message, auto const& default_) {
|
|
|
|
|
m_dialog = new QInputDialog(&view());
|
|
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
auto& dialog = static_cast<QInputDialog&>(*m_dialog);
|
2023-05-17 15:23:34 -03:00
|
|
|
dialog.setWindowTitle("Ladybird");
|
|
|
|
|
dialog.setLabelText(qstring_from_ak_string(message));
|
|
|
|
|
dialog.setTextValue(qstring_from_ak_string(default_));
|
|
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
QObject::connect(m_dialog, &QDialog::finished, this, [this](auto result) {
|
|
|
|
|
if (result == QDialog::Accepted) {
|
|
|
|
|
auto& dialog = static_cast<QInputDialog&>(*m_dialog);
|
|
|
|
|
view().prompt_closed(ak_string_from_qstring(dialog.textValue()));
|
|
|
|
|
} else {
|
|
|
|
|
view().prompt_closed({});
|
|
|
|
|
}
|
2023-05-17 15:23:34 -03:00
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
m_dialog = nullptr;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_dialog->open();
|
2023-05-17 15:23:34 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_request_set_prompt_text = [this](auto const& message) {
|
|
|
|
|
if (m_dialog && is<QInputDialog>(*m_dialog))
|
|
|
|
|
static_cast<QInputDialog&>(*m_dialog).setTextValue(qstring_from_ak_string(message));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_request_accept_dialog = [this]() {
|
|
|
|
|
if (m_dialog)
|
|
|
|
|
m_dialog->accept();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_request_dismiss_dialog = [this]() {
|
|
|
|
|
if (m_dialog)
|
|
|
|
|
m_dialog->reject();
|
|
|
|
|
};
|
|
|
|
|
|
2023-09-04 10:46:20 -03:00
|
|
|
view().on_request_color_picker = [this](Color current_color) {
|
|
|
|
|
m_dialog = new QColorDialog(QColor(current_color.red(), current_color.green(), current_color.blue()), &view());
|
|
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
auto& dialog = static_cast<QColorDialog&>(*m_dialog);
|
2023-09-04 10:46:20 -03:00
|
|
|
dialog.setWindowTitle("Ladybird");
|
|
|
|
|
dialog.setOption(QColorDialog::ShowAlphaChannel, false);
|
2024-04-24 07:53:44 -03:00
|
|
|
QObject::connect(&dialog, &QColorDialog::currentColorChanged, this, [this](QColor const& color) {
|
2023-12-11 02:53:10 -03:00
|
|
|
view().color_picker_update(Color(color.red(), color.green(), color.blue()), Web::HTML::ColorPickerUpdateState::Update);
|
|
|
|
|
});
|
2023-09-04 10:46:20 -03:00
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
QObject::connect(m_dialog, &QDialog::finished, this, [this](auto result) {
|
|
|
|
|
if (result == QDialog::Accepted) {
|
|
|
|
|
auto& dialog = static_cast<QColorDialog&>(*m_dialog);
|
|
|
|
|
view().color_picker_update(Color(dialog.selectedColor().red(), dialog.selectedColor().green(), dialog.selectedColor().blue()), Web::HTML::ColorPickerUpdateState::Closed);
|
|
|
|
|
} else {
|
|
|
|
|
view().color_picker_update({}, Web::HTML::ColorPickerUpdateState::Closed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_dialog = nullptr;
|
|
|
|
|
});
|
2023-09-04 10:46:20 -03:00
|
|
|
|
2024-10-25 14:43:53 -03:00
|
|
|
m_dialog->open();
|
2023-09-04 10:46:20 -03:00
|
|
|
};
|
|
|
|
|
|
2024-03-14 20:19:51 -03:00
|
|
|
view().on_request_file_picker = [this](auto const& accepted_file_types, auto allow_multiple_files) {
|
2024-02-25 15:09:26 -03:00
|
|
|
Vector<Web::HTML::SelectedFile> selected_files;
|
|
|
|
|
|
|
|
|
|
auto create_selected_file = [&](auto const& qfile_path) {
|
|
|
|
|
auto file_path = ak_byte_string_from_qstring(qfile_path);
|
|
|
|
|
|
2026-05-20 13:37:49 -03:00
|
|
|
if (auto file = WebView::create_selected_file(file_path); file.is_error())
|
2024-02-25 15:09:26 -03:00
|
|
|
warnln("Unable to open file {}: {}", file_path, file.error());
|
|
|
|
|
else
|
|
|
|
|
selected_files.append(file.release_value());
|
|
|
|
|
};
|
|
|
|
|
|
2024-03-14 20:19:51 -03:00
|
|
|
QStringList accepted_file_filters;
|
|
|
|
|
QMimeDatabase mime_database;
|
|
|
|
|
|
|
|
|
|
for (auto const& filter : accepted_file_types.filters) {
|
|
|
|
|
filter.visit(
|
|
|
|
|
[&](Web::HTML::FileFilter::FileType type) {
|
|
|
|
|
QString title;
|
|
|
|
|
QString filter;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case Web::HTML::FileFilter::FileType::Audio:
|
|
|
|
|
title = "Audio files";
|
|
|
|
|
filter = "audio/";
|
|
|
|
|
break;
|
|
|
|
|
case Web::HTML::FileFilter::FileType::Image:
|
|
|
|
|
title = "Image files";
|
|
|
|
|
filter = "image/";
|
|
|
|
|
break;
|
|
|
|
|
case Web::HTML::FileFilter::FileType::Video:
|
|
|
|
|
title = "Video files";
|
|
|
|
|
filter = "video/";
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList extensions;
|
|
|
|
|
|
|
|
|
|
for (auto const& mime_type : mime_database.allMimeTypes()) {
|
|
|
|
|
if (mime_type.name().startsWith(filter))
|
|
|
|
|
extensions.append(mime_type.globPatterns());
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 14:26:09 -03:00
|
|
|
accepted_file_filters.append(qformatted("{} ({})", title, extensions.join(" ")));
|
2024-03-14 20:19:51 -03:00
|
|
|
},
|
|
|
|
|
[&](Web::HTML::FileFilter::MimeType const& filter) {
|
|
|
|
|
if (auto mime_type = mime_database.mimeTypeForName(qstring_from_ak_string(filter.value)); mime_type.isValid())
|
|
|
|
|
accepted_file_filters.append(mime_type.filterString());
|
|
|
|
|
},
|
|
|
|
|
[&](Web::HTML::FileFilter::Extension const& filter) {
|
2026-05-26 14:26:09 -03:00
|
|
|
accepted_file_filters.append(qformatted("*.{}", filter.value));
|
2024-03-14 20:19:51 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
accepted_file_filters.size() > 1 ? accepted_file_filters.prepend("All files (*)") : accepted_file_filters.append("All files (*)");
|
|
|
|
|
auto filters = accepted_file_filters.join(";;");
|
|
|
|
|
|
2024-02-25 15:09:26 -03:00
|
|
|
if (allow_multiple_files == Web::HTML::AllowMultipleFiles::Yes) {
|
2024-03-14 20:19:51 -03:00
|
|
|
auto paths = QFileDialog::getOpenFileNames(this, "Select files", QDir::homePath(), filters);
|
2024-02-25 15:09:26 -03:00
|
|
|
selected_files.ensure_capacity(static_cast<size_t>(paths.size()));
|
|
|
|
|
|
|
|
|
|
for (auto const& path : paths)
|
|
|
|
|
create_selected_file(path);
|
|
|
|
|
} else {
|
2024-03-14 20:19:51 -03:00
|
|
|
auto path = QFileDialog::getOpenFileName(this, "Select file", QDir::homePath(), filters);
|
2024-02-25 15:09:26 -03:00
|
|
|
create_selected_file(path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
view().file_picker_closed(std::move(selected_files));
|
|
|
|
|
};
|
|
|
|
|
|
2024-06-09 15:25:17 -03:00
|
|
|
view().on_find_in_page = [this](auto current_match_index, auto const& total_match_count) {
|
|
|
|
|
m_find_in_page->update_result_label(current_match_index, total_match_count);
|
|
|
|
|
};
|
|
|
|
|
|
2022-09-12 04:12:04 -03:00
|
|
|
QObject::connect(focus_location_editor_action, &QAction::triggered, this, &Tab::focus_location_editor);
|
2022-10-05 10:23:41 -03:00
|
|
|
|
2023-05-17 13:37:31 -03:00
|
|
|
view().on_restore_window = [this]() {
|
2022-11-14 13:24:06 -03:00
|
|
|
m_window->showNormal();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_reposition_window = [this](auto const& position) {
|
2022-11-14 13:24:06 -03:00
|
|
|
m_window->move(position.x(), position.y());
|
2024-10-29 00:37:11 -03:00
|
|
|
view().did_update_window_rect();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_resize_window = [this](auto const& size) {
|
2022-11-14 13:24:06 -03:00
|
|
|
m_window->resize(size.width(), size.height());
|
2024-10-29 00:37:11 -03:00
|
|
|
view().did_update_window_rect();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_maximize_window = [this]() {
|
2022-11-14 13:24:06 -03:00
|
|
|
m_window->showMaximized();
|
2024-10-29 00:45:18 -03:00
|
|
|
view().did_update_window_rect();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_minimize_window = [this]() {
|
2022-11-14 13:24:06 -03:00
|
|
|
m_window->showMinimized();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_fullscreen_window = [this]() {
|
2026-05-27 10:12:53 -03:00
|
|
|
m_toolbar_container->hide();
|
2025-04-01 09:26:34 -03:00
|
|
|
m_window->fullscreen_mode().enter(this);
|
2025-03-27 11:59:17 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
view().on_exit_fullscreen_window = [this]() {
|
2026-03-16 19:40:58 -03:00
|
|
|
m_window->fullscreen_mode().exit(FullscreenMode::ExitInitiatedBy::WebContent);
|
2026-05-27 10:12:53 -03:00
|
|
|
m_toolbar_container->show();
|
2023-05-17 13:37:31 -03:00
|
|
|
};
|
2023-05-15 12:49:44 -03:00
|
|
|
|
2024-03-28 12:16:10 -03:00
|
|
|
view().on_audio_play_state_changed = [this](auto play_state) {
|
|
|
|
|
emit audio_play_state_changed(tab_index(), play_state);
|
|
|
|
|
};
|
|
|
|
|
|
2024-04-28 11:07:23 -03:00
|
|
|
auto* duplicate_tab_action = new QAction("&Duplicate Tab", this);
|
|
|
|
|
QObject::connect(duplicate_tab_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
m_window->new_tab_from_url(view().url(), Web::HTML::ActivateTab::Yes);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* move_to_start_action = new QAction("Move to &Start", this);
|
|
|
|
|
QObject::connect(move_to_start_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
m_window->move_tab(tab_index(), 0);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* move_to_end_action = new QAction("Move to &End", this);
|
|
|
|
|
QObject::connect(move_to_end_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
m_window->move_tab(tab_index(), m_window->tab_count() - 1);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* close_tab_action = new QAction("&Close Tab", this);
|
|
|
|
|
QObject::connect(close_tab_action, &QAction::triggered, this, [this]() {
|
2025-11-07 13:50:49 -03:00
|
|
|
request_close();
|
2024-04-28 11:07:23 -03:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* close_tabs_to_left_action = new QAction("C&lose Tabs to Left", this);
|
|
|
|
|
QObject::connect(close_tabs_to_left_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
for (auto i = tab_index() - 1; i >= 0; i--) {
|
2025-11-07 13:50:49 -03:00
|
|
|
m_window->request_to_close_tab(i);
|
2024-04-28 11:07:23 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* close_tabs_to_right_action = new QAction("Close Tabs to R&ight", this);
|
|
|
|
|
QObject::connect(close_tabs_to_right_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
for (auto i = m_window->tab_count() - 1; i > tab_index(); i--) {
|
2025-11-07 13:50:49 -03:00
|
|
|
m_window->request_to_close_tab(i);
|
2024-04-28 11:07:23 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
auto* close_other_tabs_action = new QAction("Cl&ose Other Tabs", this);
|
|
|
|
|
QObject::connect(close_other_tabs_action, &QAction::triggered, this, [this]() {
|
|
|
|
|
for (auto i = m_window->tab_count() - 1; i >= 0; i--) {
|
|
|
|
|
if (i == tab_index())
|
|
|
|
|
continue;
|
|
|
|
|
|
2025-11-07 13:50:49 -03:00
|
|
|
m_window->request_to_close_tab(i);
|
2024-04-28 11:07:23 -03:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
m_context_menu = new QMenu("Context menu", this);
|
2026-05-27 13:12:10 -03:00
|
|
|
m_context_menu->addAction(create_application_action(*this, WebView::Application::the().reload_action(), IncludeActionIcon::No));
|
2024-04-28 11:07:23 -03:00
|
|
|
m_context_menu->addAction(duplicate_tab_action);
|
|
|
|
|
m_context_menu->addSeparator();
|
|
|
|
|
auto* move_tab_menu = m_context_menu->addMenu("Mo&ve Tab");
|
|
|
|
|
move_tab_menu->addAction(move_to_start_action);
|
|
|
|
|
move_tab_menu->addAction(move_to_end_action);
|
|
|
|
|
m_context_menu->addSeparator();
|
|
|
|
|
m_context_menu->addAction(close_tab_action);
|
|
|
|
|
auto* close_multiple_tabs_menu = m_context_menu->addMenu("Close &Multiple Tabs");
|
|
|
|
|
close_multiple_tabs_menu->addAction(close_tabs_to_left_action);
|
|
|
|
|
close_multiple_tabs_menu->addAction(close_tabs_to_right_action);
|
|
|
|
|
close_multiple_tabs_menu->addAction(close_other_tabs_action);
|
2022-09-12 04:12:04 -03:00
|
|
|
}
|
|
|
|
|
|
2025-03-14 17:09:27 -03:00
|
|
|
Tab::~Tab() = default;
|
2023-05-17 12:54:36 -03:00
|
|
|
|
2022-09-12 04:12:04 -03:00
|
|
|
void Tab::focus_location_editor()
|
|
|
|
|
{
|
|
|
|
|
m_location_edit->setFocus();
|
|
|
|
|
m_location_edit->selectAll();
|
2022-07-06 10:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2026-05-25 16:22:07 -03:00
|
|
|
void Tab::set_window(BrowserWindow& window)
|
|
|
|
|
{
|
|
|
|
|
if (&window == m_window)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
QObject::disconnect(&m_window->hamburger_menu(), nullptr, m_hamburger_button, nullptr);
|
|
|
|
|
|
|
|
|
|
m_window = &window;
|
|
|
|
|
m_hamburger_button->setMenu(&m_window->hamburger_menu());
|
|
|
|
|
connect_hamburger_menu();
|
2026-05-25 16:22:32 -03:00
|
|
|
m_hamburger_button->setVisible(!Settings::the()->show_menubar());
|
2026-05-25 16:22:07 -03:00
|
|
|
recreate_toolbar_icons();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::connect_hamburger_menu()
|
|
|
|
|
{
|
|
|
|
|
QObject::connect(&m_window->hamburger_menu(), &QMenu::aboutToShow, m_hamburger_button, [this]() {
|
|
|
|
|
m_hamburger_button->setDown(true);
|
|
|
|
|
});
|
|
|
|
|
QObject::connect(&m_window->hamburger_menu(), &QMenu::aboutToHide, m_hamburger_button, [this]() {
|
|
|
|
|
m_hamburger_button->setDown(false);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-18 00:22:27 -03:00
|
|
|
void Tab::navigate(URL::URL const& url)
|
2022-07-06 10:38:50 -03:00
|
|
|
{
|
2024-01-30 23:15:55 -03:00
|
|
|
view().load(url);
|
2022-07-06 10:38:50 -03:00
|
|
|
}
|
|
|
|
|
|
2023-09-17 12:12:17 -03:00
|
|
|
void Tab::load_html(StringView html)
|
2023-08-28 17:14:34 -03:00
|
|
|
{
|
2023-09-17 12:12:17 -03:00
|
|
|
view().load_html(html);
|
2023-08-28 17:14:34 -03:00
|
|
|
}
|
|
|
|
|
|
2022-07-05 19:18:21 -03:00
|
|
|
void Tab::location_edit_return_pressed()
|
|
|
|
|
{
|
2026-04-24 09:36:55 -03:00
|
|
|
auto text = m_location_edit->text();
|
|
|
|
|
if (text.isEmpty())
|
2024-09-19 09:38:31 -03:00
|
|
|
return;
|
2026-04-24 09:36:55 -03:00
|
|
|
|
|
|
|
|
if (auto url = m_location_edit->url(); url.has_value())
|
|
|
|
|
navigate(*url);
|
|
|
|
|
else
|
|
|
|
|
view().load_navigation_error_page(ak_string_from_qstring(text));
|
2026-05-20 07:23:16 -03:00
|
|
|
|
|
|
|
|
view().setFocus();
|
2022-07-05 19:18:21 -03:00
|
|
|
}
|
|
|
|
|
|
2026-05-19 16:29:55 -03:00
|
|
|
QIcon Tab::tab_icon() const
|
|
|
|
|
{
|
|
|
|
|
if (m_is_loading)
|
|
|
|
|
return loading_spinner_icon(palette(), m_loading_animation_frame);
|
|
|
|
|
return m_favicon;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-24 05:02:05 -03:00
|
|
|
QString Tab::title() const
|
|
|
|
|
{
|
|
|
|
|
if (!WebView::Application::settings().config_variable_as_bool(WebView::ConfigVariableID::ShowWebContentProcessIDInTabTitle))
|
|
|
|
|
return m_title;
|
|
|
|
|
|
|
|
|
|
return QString("%1 [%2]").arg(m_title).arg(view().client().pid());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::update_tab_title()
|
|
|
|
|
{
|
|
|
|
|
emit title_changed(tab_index(), title());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::config_variable_changed(WebView::ConfigVariableID variable)
|
|
|
|
|
{
|
|
|
|
|
if (variable == WebView::ConfigVariableID::ShowWebContentProcessIDInTabTitle)
|
|
|
|
|
update_tab_title();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-19 16:29:55 -03:00
|
|
|
void Tab::set_loading(bool is_loading)
|
|
|
|
|
{
|
|
|
|
|
if (m_is_loading == is_loading)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_is_loading = is_loading;
|
|
|
|
|
m_loading_animation_frame = 0;
|
|
|
|
|
|
|
|
|
|
if (m_is_loading)
|
|
|
|
|
m_loading_animation_timer->start();
|
|
|
|
|
else
|
|
|
|
|
m_loading_animation_timer->stop();
|
|
|
|
|
|
|
|
|
|
update_tab_icon();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::update_tab_icon()
|
|
|
|
|
{
|
|
|
|
|
auto index = tab_index();
|
|
|
|
|
if (index < 0)
|
|
|
|
|
return;
|
|
|
|
|
emit favicon_changed(index, tab_icon());
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 18:47:12 -03:00
|
|
|
void Tab::open_file()
|
|
|
|
|
{
|
2024-01-30 23:29:00 -03:00
|
|
|
auto filename = QFileDialog::getOpenFileUrl(this, "Open file", QDir::homePath(), "All Files (*.*)");
|
|
|
|
|
if (filename.isValid()) {
|
|
|
|
|
navigate(ak_url_from_qurl(filename));
|
|
|
|
|
}
|
2023-05-25 18:47:12 -03:00
|
|
|
}
|
|
|
|
|
|
2022-07-05 19:18:21 -03:00
|
|
|
int Tab::tab_index()
|
|
|
|
|
{
|
2022-09-21 16:17:13 -03:00
|
|
|
return m_window->tab_index(this);
|
2022-07-05 19:18:21 -03:00
|
|
|
}
|
2022-07-08 09:14:40 -03:00
|
|
|
|
2022-09-09 09:23:36 -03:00
|
|
|
void Tab::resizeEvent(QResizeEvent* event)
|
|
|
|
|
{
|
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
|
if (m_hover_label->isVisible())
|
|
|
|
|
update_hover_label();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::update_hover_label()
|
|
|
|
|
{
|
2024-08-23 21:18:57 -03:00
|
|
|
m_hover_label->setText(QFontMetrics(m_hover_label->font()).elidedText(m_hover_label->text(), Qt::ElideRight, width() / 2 - 10));
|
2026-05-25 22:05:11 -03:00
|
|
|
m_hover_label->resize(m_hover_label->sizeHint());
|
2024-08-23 21:18:57 -03:00
|
|
|
|
|
|
|
|
auto hover_label_height = height() - m_hover_label->height();
|
2024-05-29 16:12:21 -03:00
|
|
|
if (m_find_in_page->isVisible())
|
2024-08-23 21:18:57 -03:00
|
|
|
hover_label_height -= m_find_in_page->height();
|
|
|
|
|
|
|
|
|
|
if (m_hover_label->underMouse() && m_hover_label->x() == 0)
|
|
|
|
|
m_hover_label->move(width() / 2 + (width() / 2 - m_hover_label->width()), hover_label_height);
|
|
|
|
|
else
|
|
|
|
|
m_hover_label->move(0, hover_label_height);
|
2024-05-29 16:12:21 -03:00
|
|
|
|
2022-09-09 09:23:36 -03:00
|
|
|
m_hover_label->raise();
|
|
|
|
|
}
|
2023-05-05 10:38:46 -03:00
|
|
|
|
|
|
|
|
bool Tab::event(QEvent* event)
|
|
|
|
|
{
|
|
|
|
|
if (event->type() == QEvent::PaletteChange) {
|
2026-05-25 16:21:50 -03:00
|
|
|
update_chrome_style();
|
2023-07-29 15:46:47 -03:00
|
|
|
recreate_toolbar_icons();
|
2026-05-19 16:29:55 -03:00
|
|
|
if (m_is_loading)
|
|
|
|
|
update_tab_icon();
|
2023-05-05 10:38:46 -03:00
|
|
|
return QWidget::event(event);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QWidget::event(event);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-25 16:21:50 -03:00
|
|
|
void Tab::update_chrome_style()
|
|
|
|
|
{
|
|
|
|
|
if (m_is_updating_chrome_style)
|
|
|
|
|
return;
|
|
|
|
|
m_is_updating_chrome_style = true;
|
2026-05-27 10:12:53 -03:00
|
|
|
m_toolbar_container->setStyleSheet(ChromeStyle::toolbar_container_style_sheet(palette()));
|
2026-05-25 21:35:40 -03:00
|
|
|
auto hover_surface = ChromeStyle::style_sheet_color(ChromeStyle::chrome_surface(palette()));
|
|
|
|
|
auto hover_border = ChromeStyle::style_sheet_color(ChromeStyle::chrome_border(palette()));
|
|
|
|
|
auto hover_text = ChromeStyle::style_sheet_color(ChromeStyle::chrome_text(palette()));
|
2026-05-26 14:10:34 -03:00
|
|
|
m_hover_label->setStyleSheet(qformatted("background: {}; color: {}; border: 1px solid {}; border-radius: 6px;",
|
|
|
|
|
hover_surface, hover_text, hover_border));
|
2026-05-25 16:21:50 -03:00
|
|
|
m_is_updating_chrome_style = false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-29 15:46:47 -03:00
|
|
|
void Tab::recreate_toolbar_icons()
|
2023-05-05 10:38:46 -03:00
|
|
|
{
|
2026-05-25 16:22:32 -03:00
|
|
|
m_navigate_back_action->setIcon(create_chrome_icon(ChromeIcon::Back, palette()));
|
|
|
|
|
m_navigate_forward_action->setIcon(create_chrome_icon(ChromeIcon::Forward, palette()));
|
|
|
|
|
m_reload_action->setIcon(create_chrome_icon(ChromeIcon::Reload, palette()));
|
|
|
|
|
m_hamburger_button->setIcon(create_chrome_icon(ChromeIcon::Menu, palette()));
|
2026-05-25 16:22:50 -03:00
|
|
|
if (auto* action = m_location_edit->trailing_action()) {
|
|
|
|
|
auto icon = view().toggle_bookmark_action().engaged() ? ChromeIcon::StarFilled : ChromeIcon::Star;
|
|
|
|
|
action->setIcon(create_chrome_icon(icon, palette()));
|
|
|
|
|
}
|
2023-05-05 10:38:46 -03:00
|
|
|
}
|
2023-05-17 12:54:36 -03:00
|
|
|
|
2024-05-29 16:12:21 -03:00
|
|
|
void Tab::show_find_in_page()
|
|
|
|
|
{
|
|
|
|
|
m_find_in_page->setVisible(true);
|
|
|
|
|
m_find_in_page->setFocus();
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-13 17:09:49 -03:00
|
|
|
void Tab::find_previous()
|
|
|
|
|
{
|
|
|
|
|
m_find_in_page->find_previous();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tab::find_next()
|
|
|
|
|
{
|
|
|
|
|
m_find_in_page->find_next();
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 13:50:49 -03:00
|
|
|
void Tab::request_close()
|
|
|
|
|
{
|
2026-05-26 13:03:07 -03:00
|
|
|
if (!view().needs_beforeunload_check()) {
|
|
|
|
|
auto request_close = view().prepare_for_immediate_close();
|
|
|
|
|
m_window->definitely_close_tab(tab_index());
|
|
|
|
|
Core::deferred_invoke(AK::move(request_close));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-07 13:50:49 -03:00
|
|
|
// Prevent closing on first request so WebContent can cleanly shutdown (e.g. asking if the user is sure they want
|
|
|
|
|
// to leave, closing WebSocket connections, etc.)
|
|
|
|
|
if (!m_already_requested_close) {
|
|
|
|
|
m_already_requested_close = true;
|
|
|
|
|
view().request_close();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the user has already requested a close, then respect the user's request and just close the tab.
|
|
|
|
|
// For example, the WebContent process may not be responding.
|
|
|
|
|
m_window->definitely_close_tab(tab_index());
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 14:52:59 -03:00
|
|
|
}
|