ladybird/UI/Qt/main.cpp
Andreas Kling b91ff9ebfd UI/Qt: Keep macOS app alive without windows
Disable Qt quit-on-last-window behavior on macOS and install an
application-level menu so useful commands remain available after the
last browser window closes.

Reuse shared application actions and menus for Settings, Bookmarks,
History, Help, and global appearance controls. Centralize window-aware
commands such as New Tab, New Window, Open File, Open Location, and
Reopen Recently Closed so the browser window and windowless app menu
use the same behavior. Keep the location editor focused for new blank
windows after the native window has been activated.
2026-06-22 01:13:53 +02:00

119 lines
4.2 KiB
C++

/*
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibMain/Main.h>
#include <LibWebView/Application.h>
#include <LibWebView/BrowserProcess.h>
#include <LibWebView/URL.h>
#include <LibWebView/Utilities.h>
#include <UI/Qt/Application.h>
#include <UI/Qt/BrowserWindow.h>
#include <UI/Qt/Settings.h>
#include <QCoreApplication>
#include <QtGlobal>
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
# include <QStyleHints>
#endif
namespace Ladybird {
// FIXME: Find a place to put this declaration (and other helper functions).
bool is_using_dark_system_theme(QWidget&);
bool is_using_dark_system_theme(QWidget& widget)
{
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
// Use the explicitly set or system default color scheme whenever available
auto color_scheme = QGuiApplication::styleHints()->colorScheme();
if (color_scheme != Qt::ColorScheme::Unknown)
return color_scheme == Qt::ColorScheme::Dark;
#endif
// Calculate luma based on Rec. 709 coefficients
// https://en.wikipedia.org/wiki/Rec._709#Luma_coefficients
auto color = widget.palette().color(widget.backgroundRole());
auto luma = 0.2126f * color.redF() + 0.7152f * color.greenF() + 0.0722f * color.blueF();
return luma <= 0.5f;
}
}
ErrorOr<int> ladybird_main(Main::Arguments arguments)
{
AK::set_rich_debug_enabled(true);
#ifdef AK_OS_MACOS
// The web content view is a native QRhiWidget child. Keep it from forcing
// every sibling in the tab UI to become native as well.
QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings);
#endif
auto app = TRY(Ladybird::Application::create(arguments));
app->initialize_macos_application_menu();
WebView::BrowserProcess browser_process;
WebView::copy_default_config_files(Ladybird::Settings::the()->directory());
if (auto const& browser_options = Ladybird::Application::browser_options(); !browser_options.headless_mode.has_value()) {
if (browser_options.force_new_process == WebView::ForceNewProcess::No) {
auto disposition = TRY(browser_process.connect(browser_options.raw_urls, browser_options.new_window));
if (disposition == WebView::BrowserProcess::ProcessDisposition::ExitProcess) {
outln("Opening in existing process");
return 0;
}
}
app->on_open_file = [&](auto const& file_url) {
if (auto* window = app->active_window_if_any()) {
window->view().load(file_url);
return;
}
app->new_window({ file_url });
};
browser_process.on_new_tab = [&](auto const& urls) {
if (!app->active_window_if_any()) {
app->new_window(urls);
return;
}
auto& window = *app->active_window_if_any();
for (size_t i = 0; i < urls.size(); ++i) {
window.new_tab_from_url(urls[i], (i == 0) ? Web::HTML::ActivateTab::Yes : Web::HTML::ActivateTab::No);
}
window.show();
window.activateWindow();
window.raise();
};
browser_process.on_new_window = [&](auto const& urls) {
Ladybird::WindowConfiguration configuration {};
if (auto* previous_active_window = app->active_window_if_any()) {
configuration.width = previous_active_window->width();
configuration.height = previous_active_window->height();
configuration.maximized = previous_active_window->isMaximized();
}
app->new_window(urls, configuration);
};
auto last_size = Ladybird::Settings::the()->last_size();
Ladybird::WindowConfiguration configuration {
.width = last_size.width(),
.height = last_size.height(),
.maximized = Ladybird::Settings::the()->is_maximized(),
};
if (auto last_position = Ladybird::Settings::the()->last_position(); last_position.has_value()) {
configuration.x = last_position->x();
configuration.y = last_position->y();
}
auto& window = app->new_window(browser_options.urls, configuration);
window.setWindowTitle("Ladybird");
}
return app->execute();
}