Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Libraries/LibWebView/ViewImplementation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1025,4 +1025,9 @@ void ViewImplementation::did_request_media_context_menu(Badge<WebContentClient>,
m_media_context_menu->on_activation(to_widget_position(content_position));
}

void ViewImplementation::request_close()
{
client().async_request_close(page_id());
}

}
2 changes: 2 additions & 0 deletions Libraries/LibWebView/ViewImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ class WEBVIEW_API ViewImplementation : public SettingsObserver {
// native GUI widgets as possible.
void use_native_user_style_sheet();

void request_close();

Function<void()> on_ready_to_paint;
Function<String(Web::HTML::ActivateTab, Web::HTML::WebViewHints, Optional<u64>)> on_new_web_view;
Function<void()> on_activate_tab;
Expand Down
9 changes: 9 additions & 0 deletions Services/WebContent/ConnectionFromClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,4 +1348,13 @@ void ConnectionFromClient::cookies_changed(Vector<Web::Cookie::Cookie> cookies)
}
}

// https://html.spec.whatwg.org/multipage/speculative-loading.html#nav-traversal-ui:close-a-top-level-traversable
void ConnectionFromClient::request_close(u64 page_id)
{
// Browser user agents should offer users the ability to arbitrarily close any top-level traversable in their top-level traversable set.
// For example, by clicking a "close tab" button.
if (auto page = this->page(page_id); page.has_value())
page->page().top_level_traversable()->close_top_level_traversable();
}

}
2 changes: 2 additions & 0 deletions Services/WebContent/ConnectionFromClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ class ConnectionFromClient final
virtual void system_time_zone_changed() override;
virtual void cookies_changed(Vector<Web::Cookie::Cookie>) override;

virtual void request_close(u64 page_id) override;

NonnullOwnPtr<PageHost> m_page_host;

HashMap<int, Web::FileRequest> m_requested_files {};
Expand Down
2 changes: 2 additions & 0 deletions Services/WebContent/WebContentServer.ipc
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,6 @@ endpoint WebContentServer

system_time_zone_changed() =|
cookies_changed(Vector<Web::Cookie::Cookie> cookies) =|

request_close(u64 page_id) =|
}
2 changes: 1 addition & 1 deletion UI/AppKit/Application/ApplicationDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ - (void)initializeTabController:(TabController*)controller
- (void)closeCurrentTab:(id)sender
{
auto* current_window = [NSApp keyWindow];
[current_window close];
[current_window performClose:self];
}

- (void)clearHistory:(id)sender
Expand Down
2 changes: 2 additions & 0 deletions UI/AppKit/Interface/LadybirdWebView.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,6 @@
- (void)findInPageNextMatch;
- (void)findInPagePreviousMatch;

- (void)requestClose;

@end
5 changes: 5 additions & 0 deletions UI/AppKit/Interface/LadybirdWebView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,11 @@ - (void)findInPagePreviousMatch
m_web_view_bridge->find_in_page_previous_match();
}

- (void)requestClose
{
m_web_view_bridge->request_close();
}

#pragma mark - Private methods

- (void)updateViewportRect
Expand Down
17 changes: 17 additions & 0 deletions UI/AppKit/Interface/TabController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ @interface TabController () <NSToolbarDelegate, NSSearchFieldDelegate, Autocompl
OwnPtr<WebView::Autocomplete> m_autocomplete;
}

@property (nonatomic, assign) BOOL already_requested_close;

@property (nonatomic, strong) Tab* parent;

@property (nonatomic, strong) NSToolbar* toolbar;
Expand Down Expand Up @@ -397,6 +399,21 @@ - (void)windowDidBecomeMain:(NSNotification*)notification
[delegate setActiveTab:[self tab]];
}

- (BOOL)windowShouldClose:(NSWindow*)sender
{
// 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 (!self.already_requested_close) {
self.already_requested_close = true;
[[[self tab] web_view] requestClose];
return false;
}

// 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.
return true;
}

- (void)windowWillClose:(NSNotification*)notification
{
auto* delegate = (ApplicationDelegate*)[NSApp delegate];
Expand Down
20 changes: 13 additions & 7 deletions UI/Qt/BrowserWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,8 @@ BrowserWindow::BrowserWindow(Vector<URL::URL> const& initial_urls, IsPopupWindow

set_current_tab(tab);
});
QObject::connect(m_tabs_container, &QTabWidget::tabCloseRequested, this, &BrowserWindow::close_tab);
QObject::connect(close_current_tab_action, &QAction::triggered, this, &BrowserWindow::close_current_tab);
QObject::connect(m_tabs_container, &QTabWidget::tabCloseRequested, this, &BrowserWindow::request_to_close_tab);
QObject::connect(close_current_tab_action, &QAction::triggered, this, &BrowserWindow::request_to_close_current_tab);

for (int i = 0; i <= 7; ++i) {
new QShortcut(QKeySequence(Qt::CTRL | static_cast<Qt::Key>(Qt::Key_1 + i)), this, [this, i] {
Expand Down Expand Up @@ -378,7 +378,7 @@ void BrowserWindow::activate_tab(int index)
m_tabs_container->setCurrentIndex(index);
}

void BrowserWindow::close_tab(int index)
void BrowserWindow::definitely_close_tab(int index)
{
auto* tab = m_tabs_container->widget(index);
m_tabs_container->removeTab(index);
Expand All @@ -398,9 +398,15 @@ void BrowserWindow::open_file()
m_current_tab->open_file();
}

void BrowserWindow::close_current_tab()
void BrowserWindow::request_to_close_tab(int index)
{
close_tab(m_tabs_container->currentIndex());
auto* tab = as<Tab>(m_tabs_container->widget(index));
tab->request_close();
}

void BrowserWindow::request_to_close_current_tab()
{
request_to_close_tab(m_tabs_container->currentIndex());
}

int BrowserWindow::tab_index(Tab* tab)
Expand Down Expand Up @@ -452,7 +458,7 @@ void BrowserWindow::create_close_button_for_tab(Tab* tab)

connect(button, &QPushButton::clicked, this, [this, tab]() {
auto index = m_tabs_container->indexOf(tab);
close_tab(index);
request_to_close_tab(index);
});

m_tabs_container->tabBar()->setTabButton(index, position, button);
Expand Down Expand Up @@ -625,7 +631,7 @@ bool BrowserWindow::eventFilter(QObject* obj, QEvent* event)
if (obj == m_tabs_container) {
auto const tab_index = m_tabs_container->tabBar()->tabAt(mouse_event->pos());
if (tab_index != -1) {
close_tab(tab_index);
request_to_close_tab(tab_index);
return true;
}
}
Expand Down
5 changes: 3 additions & 2 deletions UI/Qt/BrowserWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,10 @@ public slots:
Tab& new_tab_from_url(URL::URL const&, Web::HTML::ActivateTab);
Tab& new_child_tab(Web::HTML::ActivateTab, Tab& parent, Optional<u64> page_index);
void activate_tab(int index);
void close_tab(int index);
void definitely_close_tab(int index);
void move_tab(int old_index, int new_index);
void close_current_tab();
void request_to_close_tab(int index);
void request_to_close_current_tab();
void open_next_tab();
void open_previous_tab();
void open_file();
Expand Down
25 changes: 20 additions & 5 deletions UI/Qt/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client,
};

view().on_close = [this] {
m_window->close_tab(tab_index());
m_window->definitely_close_tab(tab_index());
};

view().on_link_hover = [this](auto const& url) {
Expand Down Expand Up @@ -374,20 +374,20 @@ Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client,

auto* close_tab_action = new QAction("&Close Tab", this);
QObject::connect(close_tab_action, &QAction::triggered, this, [this]() {
view().on_close();
request_close();
});

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--) {
m_window->close_tab(i);
m_window->request_to_close_tab(i);
}
});

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--) {
m_window->close_tab(i);
m_window->request_to_close_tab(i);
}
});

Expand All @@ -397,7 +397,7 @@ Tab::Tab(BrowserWindow* window, RefPtr<WebView::WebContentClient> parent_client,
if (i == tab_index())
continue;

m_window->close_tab(i);
m_window->request_to_close_tab(i);
}
});

Expand Down Expand Up @@ -513,4 +513,19 @@ void Tab::find_next()
m_find_in_page->find_next();
}

void Tab::request_close()
{
// 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());
}

}
4 changes: 4 additions & 0 deletions UI/Qt/Tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class Tab final : public QWidget {
void find_previous();
void find_next();

void request_close();

QIcon const& favicon() const { return m_favicon; }
QString const& title() const { return m_title; }

Expand Down Expand Up @@ -113,6 +115,8 @@ public slots:
QAction* m_reload_action { nullptr };

QPointer<QDialog> m_dialog;

bool m_already_requested_close { false };
};

}
Loading