mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-12-07 21:59:54 +00:00
This patch brings over the WebContent process over from SerenityOS to Ladybird, along with a new WebContentView widget that renders web content in a separate process. There's a lot of jank and FIXME material here, notably I had to re-add manually pumped Core::EventLoop instances on both sides, in order to get the IPC protocol running. This introduces a lot of latency and we should work towards replacing those loops with improved abstractions. The WebContent process is built separately here (not part of Lagom) and we provide our own main.cpp for it. Like everything, this can be better architected, it's just a starting point. :^)
185 lines
6 KiB
C++
185 lines
6 KiB
C++
/*
|
|
* Copyright (c) 2022, Andreas Kling <kling@serenityos.org>
|
|
* Copyright (c) 2022, Matthew Costa <ucosty@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include "Tab.h"
|
|
#include "BrowserWindow.h"
|
|
#include "History.h"
|
|
#include "Settings.h"
|
|
#include "Utilities.h"
|
|
#include <QCoreApplication>
|
|
#include <QFont>
|
|
#include <QFontMetrics>
|
|
#include <QPlainTextEdit>
|
|
#include <QPoint>
|
|
#include <QResizeEvent>
|
|
|
|
extern String s_serenity_resource_root;
|
|
extern Browser::Settings* s_settings;
|
|
|
|
Tab::Tab(BrowserWindow* window)
|
|
: QWidget(window)
|
|
, m_window(window)
|
|
{
|
|
m_layout = new QBoxLayout(QBoxLayout::Direction::TopToBottom, this);
|
|
m_layout->setSpacing(0);
|
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
m_view = new WebContentView;
|
|
m_toolbar = new QToolBar(this);
|
|
m_location_edit = new QLineEdit(this);
|
|
|
|
m_hover_label = new QLabel(this);
|
|
m_hover_label->hide();
|
|
m_hover_label->setFrameShape(QFrame::Shape::Box);
|
|
m_hover_label->setAutoFillBackground(true);
|
|
|
|
auto* focus_location_editor_action = new QAction("Edit Location");
|
|
focus_location_editor_action->setShortcut(QKeySequence("Ctrl+L"));
|
|
addAction(focus_location_editor_action);
|
|
|
|
m_layout->addWidget(m_toolbar);
|
|
m_layout->addWidget(m_view);
|
|
|
|
auto back_icon_path = QString("%1/res/icons/16x16/go-back.png").arg(s_serenity_resource_root.characters());
|
|
auto forward_icon_path = QString("%1/res/icons/16x16/go-forward.png").arg(s_serenity_resource_root.characters());
|
|
auto home_icon_path = QString("%1/res/icons/16x16/go-home.png").arg(s_serenity_resource_root.characters());
|
|
auto reload_icon_path = QString("%1/res/icons/16x16/reload.png").arg(s_serenity_resource_root.characters());
|
|
m_back_action = make<QAction>(QIcon(back_icon_path), "Back");
|
|
m_back_action->setEnabled(false);
|
|
m_back_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Back));
|
|
m_forward_action = make<QAction>(QIcon(forward_icon_path), "Forward");
|
|
m_forward_action->setEnabled(false);
|
|
m_forward_action->setShortcuts(QKeySequence::keyBindings(QKeySequence::StandardKey::Forward));
|
|
m_home_action = make<QAction>(QIcon(home_icon_path), "Home");
|
|
m_reload_action = make<QAction>(QIcon(reload_icon_path), "Reload");
|
|
m_reload_action->setShortcut(QKeySequence("Ctrl+R"));
|
|
|
|
m_toolbar->addAction(m_back_action);
|
|
m_toolbar->addAction(m_forward_action);
|
|
m_toolbar->addAction(m_reload_action);
|
|
m_toolbar->addAction(m_home_action);
|
|
m_toolbar->addWidget(m_location_edit);
|
|
|
|
QObject::connect(m_view, &WebContentView::link_hovered, [this](QString const& title) {
|
|
m_hover_label->setText(title);
|
|
update_hover_label();
|
|
m_hover_label->show();
|
|
});
|
|
QObject::connect(m_view, &WebContentView::link_unhovered, [this] {
|
|
m_hover_label->hide();
|
|
});
|
|
|
|
QObject::connect(m_view, &WebContentView::load_started, [this](const URL& url) {
|
|
m_location_edit->setText(url.to_string().characters());
|
|
m_history.push(url, m_title.toUtf8().data());
|
|
m_back_action->setEnabled(m_history.can_go_back());
|
|
m_forward_action->setEnabled(m_history.can_go_forward());
|
|
});
|
|
QObject::connect(m_location_edit, &QLineEdit::returnPressed, this, &Tab::location_edit_return_pressed);
|
|
QObject::connect(m_view, &WebContentView::title_changed, this, &Tab::page_title_changed);
|
|
QObject::connect(m_view, &WebContentView::favicon_changed, this, &Tab::page_favicon_changed);
|
|
|
|
QObject::connect(m_back_action, &QAction::triggered, this, &Tab::back);
|
|
QObject::connect(m_forward_action, &QAction::triggered, this, &Tab::forward);
|
|
QObject::connect(m_home_action, &QAction::triggered, this, &Tab::home);
|
|
QObject::connect(m_reload_action, &QAction::triggered, this, &Tab::reload);
|
|
QObject::connect(focus_location_editor_action, &QAction::triggered, this, &Tab::focus_location_editor);
|
|
|
|
QObject::connect(m_view, &WebContentView::got_source, this, [this](AK::URL, QString const& source) {
|
|
auto* text_edit = new QPlainTextEdit(this);
|
|
text_edit->setWindowFlags(Qt::Window);
|
|
text_edit->setFont(QFontDatabase::systemFont(QFontDatabase::SystemFont::FixedFont));
|
|
text_edit->resize(800, 600);
|
|
text_edit->setPlainText(source);
|
|
text_edit->show();
|
|
});
|
|
}
|
|
|
|
void Tab::focus_location_editor()
|
|
{
|
|
m_location_edit->setFocus();
|
|
m_location_edit->selectAll();
|
|
}
|
|
|
|
void Tab::navigate(QString url)
|
|
{
|
|
if (!url.startsWith("http://", Qt::CaseInsensitive) && !url.startsWith("https://", Qt::CaseInsensitive) && !url.startsWith("file://", Qt::CaseInsensitive))
|
|
url = "http://" + url;
|
|
view().load(akstring_from_qstring(url));
|
|
}
|
|
|
|
void Tab::back()
|
|
{
|
|
if (!m_history.can_go_back())
|
|
return;
|
|
|
|
m_history.go_back();
|
|
view().load(m_history.current().url.to_string());
|
|
}
|
|
|
|
void Tab::forward()
|
|
{
|
|
if (!m_history.can_go_forward())
|
|
return;
|
|
|
|
m_history.go_forward();
|
|
view().load(m_history.current().url.to_string());
|
|
}
|
|
|
|
void Tab::home()
|
|
{
|
|
navigate(s_settings->homepage());
|
|
}
|
|
|
|
void Tab::reload()
|
|
{
|
|
view().reload();
|
|
}
|
|
|
|
void Tab::location_edit_return_pressed()
|
|
{
|
|
navigate(m_location_edit->text());
|
|
}
|
|
|
|
void Tab::page_title_changed(QString title)
|
|
{
|
|
m_title = title;
|
|
m_history.update_title(akstring_from_qstring(m_title));
|
|
emit title_changed(tab_index(), std::move(title));
|
|
}
|
|
|
|
void Tab::page_favicon_changed(QIcon icon)
|
|
{
|
|
emit favicon_changed(tab_index(), std::move(icon));
|
|
}
|
|
|
|
int Tab::tab_index()
|
|
{
|
|
return m_window->tab_index(this);
|
|
}
|
|
|
|
void Tab::debug_request(String const& request, String const& argument)
|
|
{
|
|
if (request == "dump-history")
|
|
m_history.dump();
|
|
else
|
|
m_view->debug_request(request, argument);
|
|
}
|
|
|
|
void Tab::resizeEvent(QResizeEvent* event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
if (m_hover_label->isVisible())
|
|
update_hover_label();
|
|
}
|
|
|
|
void Tab::update_hover_label()
|
|
{
|
|
m_hover_label->resize(QFontMetrics(m_hover_label->font()).boundingRect(m_hover_label->text()).adjusted(-4, -2, 4, 2).size());
|
|
m_hover_label->move(6, height() - m_hover_label->height() - 8);
|
|
m_hover_label->raise();
|
|
}
|