2022-07-03 18:44:58 +00:00
/*
* Copyright ( c ) 2022 , Andreas Kling < kling @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2024-04-12 21:15:09 +00:00
# include "Application.h"
2022-07-03 19:26:51 +00:00
# include "BrowserWindow.h"
2023-04-24 12:51:19 +00:00
# include "EventLoopImplementationQt.h"
2022-07-14 03:41:13 +00:00
# include "Settings.h"
2023-01-27 09:41:24 +00:00
# include "WebContentView.h"
2023-08-05 16:42:26 +00:00
# include <Ladybird/HelperProcess.h>
# include <Ladybird/Utilities.h>
2022-07-03 18:36:07 +00:00
# include <LibCore/ArgsParser.h>
2022-10-05 13:23:41 +00:00
# include <LibCore/EventLoop.h>
2023-08-02 08:27:58 +00:00
# include <LibCore/Process.h>
2022-10-24 09:18:22 +00:00
# include <LibCore/System.h>
2022-10-05 13:23:41 +00:00
# include <LibGfx/Font/FontDatabase.h>
2022-07-03 18:36:07 +00:00
# include <LibMain/Main.h>
2024-04-26 21:23:20 +00:00
# include <LibWebView/ChromeProcess.h>
2023-08-31 11:07:07 +00:00
# include <LibWebView/CookieJar.h>
# include <LibWebView/Database.h>
2024-03-26 00:29:14 +00:00
# include <LibWebView/ProcessManager.h>
2023-10-13 13:52:06 +00:00
# include <LibWebView/URL.h>
2022-07-03 18:36:07 +00:00
2024-04-04 20:13:14 +00:00
# if defined(AK_OS_MACOS)
# include <Ladybird / MachPortServer.h>
# endif
2023-08-02 17:52:59 +00:00
namespace Ladybird {
bool is_using_dark_system_theme ( QWidget & widget )
{
// FIXME: Qt does not provide any method to query if the system is using a dark theme. We will have to implement
// platform-specific methods if we wish to have better detection. For now, this inspects if Qt is using a
// dark color for widget backgrounds using Rec. 709 luma 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 ;
}
}
2022-07-03 18:36:07 +00:00
2022-10-24 09:18:22 +00:00
static ErrorOr < void > handle_attached_debugger ( )
{
# ifdef AK_OS_LINUX
// Let's ignore SIGINT if we're being debugged because GDB
// incorrectly forwards the signal to us even when it's set to
// "nopass". See https://sourceware.org/bugzilla/show_bug.cgi?id=9425
// for details.
2023-08-02 08:27:58 +00:00
if ( TRY ( Core : : Process : : is_being_debugged ( ) ) ) {
dbgln ( " Debugger is attached, ignoring SIGINT " ) ;
TRY ( Core : : System : : signal ( SIGINT , SIG_IGN ) ) ;
2022-10-24 09:18:22 +00:00
}
# endif
return { } ;
}
2024-04-26 21:23:20 +00:00
static Vector < URL : : URL > sanitize_urls ( Vector < ByteString > const & raw_urls )
{
Vector < URL : : URL > sanitized_urls ;
for ( auto const & raw_url : raw_urls ) {
if ( auto url = WebView : : sanitize_url ( raw_url ) ; url . has_value ( ) )
sanitized_urls . append ( url . release_value ( ) ) ;
}
return sanitized_urls ;
}
2022-07-03 18:36:07 +00:00
ErrorOr < int > serenity_main ( Main : : Arguments arguments )
{
2023-12-11 18:19:41 +00:00
AK : : set_rich_debug_enabled ( true ) ;
2024-04-12 21:15:09 +00:00
Ladybird : : Application app ( arguments . argc , arguments . argv ) ;
2023-04-24 12:51:19 +00:00
2023-04-25 15:38:48 +00:00
Core : : EventLoopManager : : install ( * new Ladybird : : EventLoopManagerQt ) ;
2022-10-05 13:23:41 +00:00
Core : : EventLoop event_loop ;
2023-04-25 14:53:07 +00:00
static_cast < Ladybird : : EventLoopImplementationQt & > ( event_loop . impl ( ) ) . set_main_loop ( ) ;
2022-10-05 13:23:41 +00:00
2022-10-24 09:18:22 +00:00
TRY ( handle_attached_debugger ( ) ) ;
2022-10-07 23:08:29 +00:00
platform_init ( ) ;
2024-04-26 21:23:20 +00:00
Vector < ByteString > raw_urls ;
2022-12-15 14:18:52 +00:00
StringView webdriver_content_ipc_path ;
2024-02-06 15:25:22 +00:00
Vector < ByteString > certificates ;
2023-04-15 00:04:28 +00:00
bool enable_callgrind_profiling = false ;
2023-12-14 17:24:58 +00:00
bool disable_sql_database = false ;
2023-12-14 17:23:38 +00:00
bool enable_qt_networking = false ;
2024-04-20 20:46:38 +00:00
bool expose_internals_object = false ;
2023-10-27 15:28:18 +00:00
bool use_gpu_painting = false ;
2024-06-14 21:18:04 +00:00
bool use_skia_painting = false ;
2023-12-20 16:52:17 +00:00
bool debug_web_content = false ;
2024-04-16 06:02:41 +00:00
bool log_all_js_exceptions = false ;
2024-04-16 12:39:57 +00:00
bool enable_idl_tracing = false ;
2024-06-22 16:53:11 +00:00
bool enable_http_cache = false ;
2024-04-27 00:53:55 +00:00
bool new_window = false ;
2024-05-27 19:31:39 +00:00
bool force_new_process = false ;
2024-06-17 09:34:41 +00:00
bool allow_popups = false ;
2022-11-14 16:08:44 +00:00
2022-07-03 18:36:07 +00:00
Core : : ArgsParser args_parser ;
args_parser . set_general_help ( " The Ladybird web browser :^) " ) ;
2023-09-11 13:31:23 +00:00
args_parser . add_positional_argument ( raw_urls , " URLs to open " , " url " , Core : : ArgsParser : : Required : : No ) ;
2023-09-03 13:14:56 +00:00
args_parser . add_option ( webdriver_content_ipc_path , " Path to WebDriver IPC for WebContent " , " webdriver-content-path " , 0 , " path " , Core : : ArgsParser : : OptionHideMode : : CommandLineAndMarkdown ) ;
2023-04-15 00:04:28 +00:00
args_parser . add_option ( enable_callgrind_profiling , " Enable Callgrind profiling " , " enable-callgrind-profiling " , ' P ' ) ;
2024-04-20 20:34:56 +00:00
args_parser . add_option ( disable_sql_database , " Disable SQL database " , " disable-sql-database " ) ;
args_parser . add_option ( enable_qt_networking , " Enable Qt as the backend networking service " , " enable-qt-networking " ) ;
args_parser . add_option ( use_gpu_painting , " Enable GPU painting " , " enable-gpu-painting " ) ;
2024-06-14 21:18:04 +00:00
args_parser . add_option ( use_skia_painting , " Enable Skia painting " , " enable-skia-painting " ) ;
2024-04-20 20:34:56 +00:00
args_parser . add_option ( debug_web_content , " Wait for debugger to attach to WebContent " , " debug-web-content " ) ;
2024-02-06 15:25:22 +00:00
args_parser . add_option ( certificates , " Path to a certificate file " , " certificate " , ' C ' , " certificate " ) ;
2024-04-20 20:34:56 +00:00
args_parser . add_option ( log_all_js_exceptions , " Log all JavaScript exceptions " , " log-all-js-exceptions " ) ;
args_parser . add_option ( enable_idl_tracing , " Enable IDL tracing " , " enable-idl-tracing " ) ;
2024-06-22 16:53:11 +00:00
args_parser . add_option ( enable_http_cache , " Enable HTTP cache " , " enable-http-cache " ) ;
2024-04-20 20:46:38 +00:00
args_parser . add_option ( expose_internals_object , " Expose internals object " , " expose-internals-object " ) ;
2024-04-27 00:53:55 +00:00
args_parser . add_option ( new_window , " Force opening in a new window " , " new-window " , ' n ' ) ;
2024-05-27 19:31:39 +00:00
args_parser . add_option ( force_new_process , " Force creation of new browser/chrome process " , " force-new-process " ) ;
2024-06-17 09:34:41 +00:00
args_parser . add_option ( allow_popups , " Disable popup blocking by default " , " allow-popups " ) ;
2022-07-03 18:36:07 +00:00
args_parser . parse ( arguments ) ;
2024-04-26 21:23:20 +00:00
WebView : : ChromeProcess chrome_process ;
2024-05-27 19:31:39 +00:00
if ( ! force_new_process & & TRY ( chrome_process . connect ( raw_urls , new_window ) ) = = WebView : : ChromeProcess : : ProcessDisposition : : ExitProcess ) {
2024-04-26 21:23:20 +00:00
outln ( " Opening in existing process " ) ;
return 0 ;
}
2024-04-27 00:53:55 +00:00
chrome_process . on_new_tab = [ & ] ( auto const & raw_urls ) {
auto & window = app . active_window ( ) ;
auto urls = sanitize_urls ( raw_urls ) ;
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 ( ) ;
} ;
app . on_open_file = [ & ] ( auto file_url ) {
auto & window = app . active_window ( ) ;
window . view ( ) . load ( file_url ) ;
2024-04-26 21:23:20 +00:00
} ;
2024-04-04 20:13:14 +00:00
WebView : : ProcessManager : : initialize ( ) ;
# if defined(AK_OS_MACOS)
auto mach_port_server = make < Ladybird : : MachPortServer > ( ) ;
set_mach_server_name ( mach_port_server - > server_port_name ( ) ) ;
mach_port_server - > on_receive_child_mach_port = [ ] ( auto pid , auto port ) {
WebView : : ProcessManager : : the ( ) . add_process ( pid , move ( port ) ) ;
} ;
2024-06-20 18:34:51 +00:00
mach_port_server - > on_receive_backing_stores = [ ] ( Ladybird : : MachPortServer : : BackingStoresMessage message ) {
auto view = WebView : : WebContentClient : : view_for_pid_and_page_id ( message . pid , message . page_id ) ;
view - > did_allocate_iosurface_backing_stores ( message . front_backing_store_id , move ( message . front_backing_store_port ) , message . back_backing_store_id , move ( message . back_backing_store_port ) ) ;
} ;
2024-04-04 20:13:14 +00:00
# endif
2023-08-31 11:07:07 +00:00
RefPtr < WebView : : Database > database ;
2024-06-04 20:34:32 +00:00
if ( ! disable_sql_database )
database = TRY ( WebView : : Database : : create ( ) ) ;
2023-04-20 18:26:06 +00:00
2023-08-31 11:07:07 +00:00
auto cookie_jar = database ? TRY ( WebView : : CookieJar : : create ( * database ) ) : WebView : : CookieJar : : create ( ) ;
2022-12-05 18:09:42 +00:00
2024-04-15 23:39:48 +00:00
// NOTE: WebWorker *always* needs a request server connection, even if WebContent uses Qt Networking
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
auto request_server_paths = TRY ( get_paths_for_helper_process ( " RequestServer " sv ) ) ;
auto protocol_client = TRY ( launch_request_server_process ( request_server_paths , s_serenity_resource_root , certificates ) ) ;
2024-06-26 19:44:42 +00:00
app . request_server_client = move ( protocol_client ) ;
TRY ( app . initialize_image_decoder ( ) ) ;
2024-04-15 23:39:48 +00:00
2024-01-16 17:55:40 +00:00
StringBuilder command_line_builder ;
command_line_builder . join ( ' ' , arguments . strings ) ;
2023-12-01 17:18:40 +00:00
Ladybird : : WebContentOptions web_content_options {
2024-01-16 17:55:40 +00:00
. command_line = MUST ( command_line_builder . to_string ( ) ) ,
. executable_path = MUST ( String : : from_byte_string ( MUST ( Core : : System : : current_executable_path ( ) ) ) ) ,
2023-12-01 17:18:40 +00:00
. enable_callgrind_profiling = enable_callgrind_profiling ? Ladybird : : EnableCallgrindProfiling : : Yes : Ladybird : : EnableCallgrindProfiling : : No ,
. enable_gpu_painting = use_gpu_painting ? Ladybird : : EnableGPUPainting : : Yes : Ladybird : : EnableGPUPainting : : No ,
2024-06-14 21:18:04 +00:00
. enable_skia_painting = use_skia_painting ? Ladybird : : EnableSkiaPainting : : Yes : Ladybird : : EnableSkiaPainting : : No ,
2023-12-14 17:23:38 +00:00
. use_lagom_networking = enable_qt_networking ? Ladybird : : UseLagomNetworking : : No : Ladybird : : UseLagomNetworking : : Yes ,
2023-12-20 16:52:17 +00:00
. wait_for_debugger = debug_web_content ? Ladybird : : WaitForDebugger : : Yes : Ladybird : : WaitForDebugger : : No ,
2024-04-16 06:02:41 +00:00
. log_all_js_exceptions = log_all_js_exceptions ? Ladybird : : LogAllJSExceptions : : Yes : Ladybird : : LogAllJSExceptions : : No ,
2024-04-16 12:39:57 +00:00
. enable_idl_tracing = enable_idl_tracing ? Ladybird : : EnableIDLTracing : : Yes : Ladybird : : EnableIDLTracing : : No ,
2024-06-22 16:53:11 +00:00
. enable_http_cache = enable_http_cache ? Ladybird : : EnableHTTPCache : : Yes : Ladybird : : EnableHTTPCache : : No ,
2024-04-20 20:46:38 +00:00
. expose_internals_object = expose_internals_object ? Ladybird : : ExposeInternalsObject : : Yes : Ladybird : : ExposeInternalsObject : : No ,
2023-12-01 17:18:40 +00:00
} ;
2024-04-27 00:53:55 +00:00
chrome_process . on_new_window = [ & ] ( auto const & urls ) {
2024-06-17 09:34:41 +00:00
app . new_window ( sanitize_urls ( urls ) , * cookie_jar , web_content_options , webdriver_content_ipc_path , allow_popups ) ;
2024-04-26 21:23:20 +00:00
} ;
2024-06-17 09:34:41 +00:00
auto & window = app . new_window ( sanitize_urls ( raw_urls ) , * cookie_jar , web_content_options , webdriver_content_ipc_path , allow_popups ) ;
2024-04-27 00:53:55 +00:00
window . setWindowTitle ( " Ladybird " ) ;
2023-11-13 19:45:38 +00:00
2023-05-29 09:05:30 +00:00
if ( Ladybird : : Settings : : the ( ) - > is_maximized ( ) ) {
2023-08-09 10:23:32 +00:00
window . showMaximized ( ) ;
} else {
2023-05-29 09:05:30 +00:00
auto last_position = Ladybird : : Settings : : the ( ) - > last_position ( ) ;
2023-08-09 10:23:32 +00:00
if ( last_position . has_value ( ) )
window . move ( last_position . value ( ) ) ;
2023-05-29 09:05:30 +00:00
window . resize ( Ladybird : : Settings : : the ( ) - > last_size ( ) ) ;
2023-08-09 10:23:32 +00:00
}
2022-07-03 18:36:07 +00:00
window . show ( ) ;
2023-04-24 12:51:19 +00:00
return event_loop . exec ( ) ;
2022-07-03 18:36:07 +00:00
}