2022-07-05 22:18:21 +00:00
/*
2023-01-11 19:09:52 +00:00
* Copyright ( c ) 2022 - 2023 , Andreas Kling < kling @ serenityos . org >
2022-07-05 22:18:21 +00:00
* Copyright ( c ) 2022 , Matthew Costa < ucosty @ gmail . com >
2022-07-14 04:08:30 +00:00
* Copyright ( c ) 2022 , Filiph Sandström < filiph . sandstrom @ filfatstudios . com >
2023-01-12 14:39:53 +00:00
* Copyright ( c ) 2023 , Linus Groh < linusg @ serenityos . org >
2022-07-05 22:18:21 +00:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-07-03 19:26:51 +00:00
# include "BrowserWindow.h"
2023-04-23 01:57:08 +00:00
# include "ConsoleWidget.h"
2022-07-14 04:08:30 +00:00
# include "Settings.h"
# include "SettingsDialog.h"
2022-09-26 14:57:44 +00:00
# include "Utilities.h"
2022-10-05 13:23:41 +00:00
# include "WebContentView.h"
2022-09-13 16:18:32 +00:00
# include <AK/TypeCasts.h>
2022-12-05 18:09:42 +00:00
# include <Browser/CookieJar.h>
2023-01-12 18:27:34 +00:00
# include <LibWeb/CSS/PreferredColorScheme.h>
2022-09-26 14:57:44 +00:00
# include <LibWeb/Loader/ResourceLoader.h>
2022-07-05 19:10:50 +00:00
# include <QAction>
2022-09-19 08:48:02 +00:00
# include <QActionGroup>
2023-01-11 19:09:52 +00:00
# include <QClipboard>
# include <QGuiApplication>
2022-09-26 14:57:44 +00:00
# include <QInputDialog>
2022-07-09 15:46:11 +00:00
# include <QPlainTextEdit>
2023-02-05 02:26:20 +00:00
# include <QTabBar>
2022-07-03 19:26:51 +00:00
2022-12-04 18:43:54 +00:00
extern DeprecatedString s_serenity_resource_root ;
2022-07-14 04:08:30 +00:00
extern Browser : : Settings * s_settings ;
2022-07-08 12:14:40 +00:00
2023-04-15 00:04:28 +00:00
BrowserWindow : : BrowserWindow ( Browser : : CookieJar & cookie_jar , StringView webdriver_content_ipc_path , WebView : : EnableCallgrindProfiling enable_callgrind_profiling )
2022-12-05 18:09:42 +00:00
: m_cookie_jar ( cookie_jar )
2022-12-15 14:18:52 +00:00
, m_webdriver_content_ipc_path ( webdriver_content_ipc_path )
2023-04-15 00:04:28 +00:00
, m_enable_callgrind_profiling ( enable_callgrind_profiling )
2022-07-03 19:26:51 +00:00
{
2022-10-01 18:46:24 +00:00
m_tabs_container = new QTabWidget ( this ) ;
2023-02-05 02:26:20 +00:00
m_tabs_container - > installEventFilter ( this ) ;
2022-07-05 22:18:21 +00:00
m_tabs_container - > setElideMode ( Qt : : TextElideMode : : ElideRight ) ;
m_tabs_container - > setMovable ( true ) ;
m_tabs_container - > setTabsClosable ( true ) ;
2022-09-09 12:07:24 +00:00
m_tabs_container - > setDocumentMode ( true ) ;
2022-09-22 16:23:59 +00:00
m_tabs_container - > setTabBarAutoHide ( true ) ;
2022-07-12 09:41:11 +00:00
2022-07-08 12:14:40 +00:00
auto * menu = menuBar ( ) - > addMenu ( " &File " ) ;
2022-07-07 00:55:21 +00:00
2022-10-01 18:46:24 +00:00
auto * new_tab_action = new QAction ( " New &Tab " , this ) ;
2023-05-25 01:22:06 +00:00
new_tab_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/new-tab.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 18:39:07 +00:00
new_tab_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : AddTab ) ) ;
2022-07-07 00:55:21 +00:00
menu - > addAction ( new_tab_action ) ;
2022-10-01 18:46:24 +00:00
auto * settings_action = new QAction ( " &Settings " , this ) ;
2023-05-25 01:22:06 +00:00
settings_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/settings.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 18:39:07 +00:00
settings_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Preferences ) ) ;
2022-07-14 04:08:30 +00:00
menu - > addAction ( settings_action ) ;
2022-10-01 18:46:24 +00:00
auto * close_current_tab_action = new QAction ( " Close Current Tab " , this ) ;
2023-05-25 01:22:06 +00:00
close_current_tab_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/close-tab.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 18:39:07 +00:00
close_current_tab_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Close ) ) ;
2022-07-19 10:16:46 +00:00
menu - > addAction ( close_current_tab_action ) ;
2022-10-01 18:46:24 +00:00
auto * quit_action = new QAction ( " &Quit " , this ) ;
2023-01-12 18:39:07 +00:00
quit_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Quit ) ) ;
2022-07-07 00:55:21 +00:00
menu - > addAction ( quit_action ) ;
2022-07-05 19:10:50 +00:00
2023-01-11 19:09:52 +00:00
auto * edit_menu = menuBar ( ) - > addMenu ( " &Edit " ) ;
2023-05-15 15:49:44 +00:00
m_copy_selection_action = make < QAction > ( " &Copy " , this ) ;
2023-05-25 01:22:06 +00:00
m_copy_selection_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/edit-copy.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-05-15 15:49:44 +00:00
m_copy_selection_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Copy ) ) ;
edit_menu - > addAction ( m_copy_selection_action ) ;
QObject : : connect ( m_copy_selection_action , & QAction : : triggered , this , & BrowserWindow : : copy_selected_text ) ;
2023-01-11 19:09:52 +00:00
2023-05-15 15:49:44 +00:00
m_select_all_action = make < QAction > ( " Select &All " , this ) ;
2023-05-25 01:22:06 +00:00
m_select_all_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/select-all.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-05-15 15:49:44 +00:00
m_select_all_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : SelectAll ) ) ;
edit_menu - > addAction ( m_select_all_action ) ;
QObject : : connect ( m_select_all_action , & QAction : : triggered , this , & BrowserWindow : : select_all ) ;
2023-01-11 19:09:52 +00:00
2022-09-12 07:22:43 +00:00
auto * view_menu = menuBar ( ) - > addMenu ( " &View " ) ;
2022-10-01 18:46:24 +00:00
auto * open_next_tab_action = new QAction ( " Open &Next Tab " , this ) ;
2022-09-12 07:22:43 +00:00
open_next_tab_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : Key_PageDown ) ) ;
view_menu - > addAction ( open_next_tab_action ) ;
QObject : : connect ( open_next_tab_action , & QAction : : triggered , this , & BrowserWindow : : open_next_tab ) ;
2022-10-01 18:46:24 +00:00
auto * open_previous_tab_action = new QAction ( " Open &Previous Tab " , this ) ;
2022-09-12 07:22:43 +00:00
open_previous_tab_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : Key_PageUp ) ) ;
view_menu - > addAction ( open_previous_tab_action ) ;
QObject : : connect ( open_previous_tab_action , & QAction : : triggered , this , & BrowserWindow : : open_previous_tab ) ;
2022-09-19 08:48:02 +00:00
view_menu - > addSeparator ( ) ;
2023-03-26 17:56:17 +00:00
m_zoom_menu = view_menu - > addMenu ( " &Zoom " ) ;
2023-01-12 14:39:53 +00:00
auto * zoom_in_action = new QAction ( " Zoom &In " , this ) ;
2023-05-25 01:22:06 +00:00
zoom_in_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/zoom-in.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 18:52:24 +00:00
auto zoom_in_shortcuts = QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : ZoomIn ) ;
zoom_in_shortcuts . append ( QKeySequence ( Qt : : CTRL | Qt : : Key_Equal ) ) ;
zoom_in_action - > setShortcuts ( zoom_in_shortcuts ) ;
2023-03-26 17:56:17 +00:00
m_zoom_menu - > addAction ( zoom_in_action ) ;
2023-01-12 14:39:53 +00:00
QObject : : connect ( zoom_in_action , & QAction : : triggered , this , & BrowserWindow : : zoom_in ) ;
auto * zoom_out_action = new QAction ( " Zoom &Out " , this ) ;
2023-05-25 01:22:06 +00:00
zoom_out_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/zoom-out.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 18:39:07 +00:00
zoom_out_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : ZoomOut ) ) ;
2023-03-26 17:56:17 +00:00
m_zoom_menu - > addAction ( zoom_out_action ) ;
2023-01-12 14:39:53 +00:00
QObject : : connect ( zoom_out_action , & QAction : : triggered , this , & BrowserWindow : : zoom_out ) ;
auto * reset_zoom_action = new QAction ( " &Reset Zoom " , this ) ;
2023-05-25 01:22:06 +00:00
reset_zoom_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/zoom-reset.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-01-12 14:39:53 +00:00
reset_zoom_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : Key_0 ) ) ;
2023-03-26 17:56:17 +00:00
m_zoom_menu - > addAction ( reset_zoom_action ) ;
2023-01-12 14:39:53 +00:00
QObject : : connect ( reset_zoom_action , & QAction : : triggered , this , & BrowserWindow : : reset_zoom ) ;
view_menu - > addSeparator ( ) ;
2022-09-19 08:48:02 +00:00
auto * color_scheme_menu = view_menu - > addMenu ( " &Color Scheme " ) ;
2022-09-26 14:28:01 +00:00
auto * color_scheme_group = new QActionGroup ( this ) ;
2022-09-19 08:48:02 +00:00
2022-10-01 18:46:24 +00:00
auto * auto_color_scheme = new QAction ( " &Auto " , this ) ;
2022-09-19 08:48:02 +00:00
auto_color_scheme - > setCheckable ( true ) ;
2022-09-26 14:28:01 +00:00
color_scheme_group - > addAction ( auto_color_scheme ) ;
2022-09-19 08:48:02 +00:00
color_scheme_menu - > addAction ( auto_color_scheme ) ;
QObject : : connect ( auto_color_scheme , & QAction : : triggered , this , & BrowserWindow : : enable_auto_color_scheme ) ;
2022-10-01 18:46:24 +00:00
auto * light_color_scheme = new QAction ( " &Light " , this ) ;
2022-09-19 08:48:02 +00:00
light_color_scheme - > setCheckable ( true ) ;
2022-09-26 14:28:01 +00:00
color_scheme_group - > addAction ( light_color_scheme ) ;
2022-09-19 08:48:02 +00:00
color_scheme_menu - > addAction ( light_color_scheme ) ;
QObject : : connect ( light_color_scheme , & QAction : : triggered , this , & BrowserWindow : : enable_light_color_scheme ) ;
2022-10-01 18:46:24 +00:00
auto * dark_color_scheme = new QAction ( " &Dark " , this ) ;
2022-09-19 08:48:02 +00:00
dark_color_scheme - > setCheckable ( true ) ;
2022-09-26 14:28:01 +00:00
color_scheme_group - > addAction ( dark_color_scheme ) ;
2022-09-19 08:48:02 +00:00
color_scheme_menu - > addAction ( dark_color_scheme ) ;
QObject : : connect ( dark_color_scheme , & QAction : : triggered , this , & BrowserWindow : : enable_dark_color_scheme ) ;
auto_color_scheme - > setChecked ( true ) ;
2022-07-09 15:46:11 +00:00
auto * inspect_menu = menuBar ( ) - > addMenu ( " &Inspect " ) ;
2023-05-15 15:49:44 +00:00
m_view_source_action = make < QAction > ( " View &Source " , this ) ;
m_view_source_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/filetype-html.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
m_view_source_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : Key_U ) ) ;
inspect_menu - > addAction ( m_view_source_action ) ;
QObject : : connect ( m_view_source_action , & QAction : : triggered , this , [ this ] {
2022-07-09 15:46:11 +00:00
if ( m_current_tab ) {
2022-10-05 13:23:41 +00:00
m_current_tab - > view ( ) . get_source ( ) ;
2022-07-09 15:46:11 +00:00
}
} ) ;
2022-10-01 18:46:24 +00:00
auto * js_console_action = new QAction ( " Show &JS Console " , this ) ;
2022-07-17 12:47:26 +00:00
js_console_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/filetype-javascript.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
js_console_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_J ) ) ;
inspect_menu - > addAction ( js_console_action ) ;
QObject : : connect ( js_console_action , & QAction : : triggered , this , [ this ] {
if ( m_current_tab ) {
2023-05-17 15:54:36 +00:00
m_current_tab - > show_console_window ( ) ;
2022-07-17 12:47:26 +00:00
}
} ) ;
2022-09-25 10:17:53 +00:00
auto * inspector_action = new QAction ( " Open &Inspector " ) ;
inspector_action - > setIcon ( QIcon ( QString ( " %1/res/icons/browser/dom-tree.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
inspector_action - > setShortcut ( QKeySequence ( " Ctrl+Shift+I " ) ) ;
inspect_menu - > addAction ( inspector_action ) ;
QObject : : connect ( inspector_action , & QAction : : triggered , this , [ this ] {
if ( m_current_tab ) {
2023-05-17 15:54:36 +00:00
m_current_tab - > show_inspector_window ( ) ;
2022-09-25 10:17:53 +00:00
}
} ) ;
2022-07-08 12:14:40 +00:00
auto * debug_menu = menuBar ( ) - > addMenu ( " &Debug " ) ;
2022-10-01 18:46:24 +00:00
auto * dump_dom_tree_action = new QAction ( " Dump DOM Tree " , this ) ;
2022-07-08 12:14:40 +00:00
dump_dom_tree_action - > setIcon ( QIcon ( QString ( " %1/res/icons/browser/dom-tree.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_dom_tree_action ) ;
QObject : : connect ( dump_dom_tree_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-dom-tree " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_layout_tree_action = new QAction ( " Dump Layout Tree " , this ) ;
2022-07-08 12:14:40 +00:00
dump_layout_tree_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/layout.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_layout_tree_action ) ;
QObject : : connect ( dump_layout_tree_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-layout-tree " ) ;
} ) ;
2023-03-18 19:22:58 +00:00
auto * dump_paint_tree_action = new QAction ( " Dump Paint Tree " , this ) ;
2023-05-25 01:22:06 +00:00
dump_paint_tree_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/layout.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
2023-03-18 19:22:58 +00:00
debug_menu - > addAction ( dump_paint_tree_action ) ;
QObject : : connect ( dump_paint_tree_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-paint-tree " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_stacking_context_tree_action = new QAction ( " Dump Stacking Context Tree " , this ) ;
2022-07-08 12:14:40 +00:00
dump_stacking_context_tree_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/layers.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_stacking_context_tree_action ) ;
QObject : : connect ( dump_stacking_context_tree_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-stacking-context-tree " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_style_sheets_action = new QAction ( " Dump Style Sheets " , this ) ;
2022-07-08 12:14:40 +00:00
dump_style_sheets_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/filetype-css.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_style_sheets_action ) ;
QObject : : connect ( dump_style_sheets_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-style-sheets " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_history_action = new QAction ( " Dump History " , this ) ;
2022-07-08 12:14:40 +00:00
dump_history_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/history.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_history_action ) ;
QObject : : connect ( dump_history_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-history " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_cookies_action = new QAction ( " Dump Cookies " , this ) ;
2022-07-08 12:14:40 +00:00
dump_cookies_action - > setIcon ( QIcon ( QString ( " %1/res/icons/browser/cookie.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_cookies_action ) ;
QObject : : connect ( dump_cookies_action , & QAction : : triggered , this , [ this ] {
2022-10-11 08:53:28 +00:00
m_cookie_jar . dump_cookies ( ) ;
2022-07-08 12:14:40 +00:00
} ) ;
2022-10-01 18:46:24 +00:00
auto * dump_local_storage_action = new QAction ( " Dump Local Storage " , this ) ;
2022-07-08 12:14:40 +00:00
dump_local_storage_action - > setIcon ( QIcon ( QString ( " %1/res/icons/browser/local-storage.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( dump_local_storage_action ) ;
QObject : : connect ( dump_local_storage_action , & QAction : : triggered , this , [ this ] {
debug_request ( " dump-local-storage " ) ;
} ) ;
debug_menu - > addSeparator ( ) ;
2022-10-01 18:46:24 +00:00
auto * show_line_box_borders_action = new QAction ( " Show Line Box Borders " , this ) ;
2022-07-08 12:14:40 +00:00
show_line_box_borders_action - > setCheckable ( true ) ;
debug_menu - > addAction ( show_line_box_borders_action ) ;
QObject : : connect ( show_line_box_borders_action , & QAction : : triggered , this , [ this , show_line_box_borders_action ] {
bool state = show_line_box_borders_action - > isChecked ( ) ;
debug_request ( " set-line-box-borders " , state ? " on " : " off " ) ;
} ) ;
debug_menu - > addSeparator ( ) ;
2022-10-01 18:46:24 +00:00
auto * collect_garbage_action = new QAction ( " Collect Garbage " , this ) ;
2022-10-16 13:35:44 +00:00
collect_garbage_action - > setShortcut ( QKeySequence ( Qt : : CTRL | Qt : : SHIFT | Qt : : Key_G ) ) ;
2022-07-08 12:14:40 +00:00
collect_garbage_action - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/trash-can.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( collect_garbage_action ) ;
QObject : : connect ( collect_garbage_action , & QAction : : triggered , this , [ this ] {
debug_request ( " collect-garbage " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * clear_cache_action = new QAction ( " Clear Cache " , this ) ;
2022-07-08 12:14:40 +00:00
clear_cache_action - > setIcon ( QIcon ( QString ( " %1/res/icons/browser/clear-cache.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
debug_menu - > addAction ( clear_cache_action ) ;
QObject : : connect ( clear_cache_action , & QAction : : triggered , this , [ this ] {
debug_request ( " clear-cache " ) ;
} ) ;
2022-09-26 14:57:44 +00:00
auto * spoof_user_agent_menu = debug_menu - > addMenu ( " Spoof User Agent " ) ;
spoof_user_agent_menu - > setIcon ( QIcon ( QString ( " %1/res/icons/16x16/spoof.png " ) . arg ( s_serenity_resource_root . characters ( ) ) ) ) ;
auto * user_agent_group = new QActionGroup ( this ) ;
auto add_user_agent = [ this , & user_agent_group , & spoof_user_agent_menu ] ( auto & name , auto & user_agent ) {
auto * action = new QAction ( name ) ;
action - > setCheckable ( true ) ;
user_agent_group - > addAction ( action ) ;
spoof_user_agent_menu - > addAction ( action ) ;
QObject : : connect ( action , & QAction : : triggered , this , [ this , user_agent ] {
debug_request ( " spoof-user-agent " , user_agent ) ;
debug_request ( " clear-cache " ) ; // clear the cache to ensure requests are re-done with the new user agent
} ) ;
return action ;
} ;
auto * disable_spoofing = add_user_agent ( " Disabled " , Web : : default_user_agent ) ;
disable_spoofing - > setChecked ( true ) ;
add_user_agent ( " Chrome Linux Desktop " , " Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36 " ) ;
add_user_agent ( " Firefox Linux Desktop " , " Mozilla/5.0 (X11; Linux i686; rv:87.0) Gecko/20100101 Firefox/87.0 " ) ;
add_user_agent ( " Safari macOS Desktop " , " Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.3 Safari/605.1.15 " ) ;
add_user_agent ( " Chrome Android Mobile " , " Mozilla/5.0 (Linux; Android 10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.66 Mobile Safari/537.36 " ) ;
add_user_agent ( " Firefox Android Mobile " , " Mozilla/5.0 (Android 11; Mobile; rv:68.0) Gecko/68.0 Firefox/86.0 " ) ;
add_user_agent ( " Safari iOS Mobile " , " Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0 Mobile/15E148 Safari/604.1 " ) ;
auto * custom_user_agent_action = new QAction ( " Custom... " ) ;
custom_user_agent_action - > setCheckable ( true ) ;
user_agent_group - > addAction ( custom_user_agent_action ) ;
spoof_user_agent_menu - > addAction ( custom_user_agent_action ) ;
QObject : : connect ( custom_user_agent_action , & QAction : : triggered , this , [ this , disable_spoofing ] {
auto user_agent = QInputDialog : : getText ( this , " Custom User Agent " , " Enter User Agent: " ) ;
if ( ! user_agent . isEmpty ( ) ) {
2022-12-04 18:43:54 +00:00
debug_request ( " spoof-user-agent " , ak_deprecated_string_from_qstring ( user_agent ) ) ;
2022-09-26 14:57:44 +00:00
debug_request ( " clear-cache " ) ; // clear the cache to ensure requests are re-done with the new user agent
} else {
disable_spoofing - > activate ( QAction : : Trigger ) ;
}
} ) ;
2022-07-08 12:14:40 +00:00
debug_menu - > addSeparator ( ) ;
2022-10-01 18:46:24 +00:00
auto * enable_scripting_action = new QAction ( " Enable Scripting " , this ) ;
2022-07-08 12:14:40 +00:00
enable_scripting_action - > setCheckable ( true ) ;
enable_scripting_action - > setChecked ( true ) ;
debug_menu - > addAction ( enable_scripting_action ) ;
QObject : : connect ( enable_scripting_action , & QAction : : triggered , this , [ this , enable_scripting_action ] {
bool state = enable_scripting_action - > isChecked ( ) ;
debug_request ( " scripting " , state ? " on " : " off " ) ;
} ) ;
2022-11-14 23:49:05 +00:00
auto * block_pop_ups_action = new QAction ( " Block Pop-ups " , this ) ;
block_pop_ups_action - > setCheckable ( true ) ;
block_pop_ups_action - > setChecked ( true ) ;
debug_menu - > addAction ( block_pop_ups_action ) ;
QObject : : connect ( block_pop_ups_action , & QAction : : triggered , this , [ this , block_pop_ups_action ] {
bool state = block_pop_ups_action - > isChecked ( ) ;
debug_request ( " block-pop-ups " , state ? " on " : " off " ) ;
} ) ;
2022-10-01 18:46:24 +00:00
auto * enable_same_origin_policy_action = new QAction ( " Enable Same-Origin Policy " , this ) ;
2022-07-08 12:14:40 +00:00
enable_same_origin_policy_action - > setCheckable ( true ) ;
debug_menu - > addAction ( enable_same_origin_policy_action ) ;
QObject : : connect ( enable_same_origin_policy_action , & QAction : : triggered , this , [ this , enable_same_origin_policy_action ] {
bool state = enable_same_origin_policy_action - > isChecked ( ) ;
debug_request ( " same-origin-policy " , state ? " on " : " off " ) ;
} ) ;
2023-01-08 10:21:55 +00:00
QObject : : connect ( new_tab_action , & QAction : : triggered , this , [ this ] {
2023-03-20 22:39:20 +00:00
new_tab ( s_settings - > new_tab_page ( ) , Web : : HTML : : ActivateTab : : Yes ) ;
2023-01-08 10:21:55 +00:00
} ) ;
2022-07-14 04:08:30 +00:00
QObject : : connect ( settings_action , & QAction : : triggered , this , [ this ] {
new SettingsDialog ( this ) ;
} ) ;
2022-07-05 22:18:21 +00:00
QObject : : connect ( quit_action , & QAction : : triggered , this , & QMainWindow : : close ) ;
QObject : : connect ( m_tabs_container , & QTabWidget : : currentChanged , [ this ] ( int index ) {
2022-07-12 09:42:40 +00:00
setWindowTitle ( QString ( " %1 - Ladybird " ) . arg ( m_tabs_container - > tabText ( index ) ) ) ;
2022-07-05 22:18:21 +00:00
setWindowIcon ( m_tabs_container - > tabIcon ( index ) ) ;
2023-03-26 17:56:17 +00:00
set_current_tab ( verify_cast < Tab > ( m_tabs_container - > widget ( index ) ) ) ;
2022-07-05 22:18:21 +00:00
} ) ;
2022-07-06 13:36:49 +00:00
QObject : : connect ( m_tabs_container , & QTabWidget : : tabCloseRequested , this , & BrowserWindow : : close_tab ) ;
2022-07-19 10:16:46 +00:00
QObject : : connect ( close_current_tab_action , & QAction : : triggered , this , & BrowserWindow : : close_current_tab ) ;
2022-07-03 19:26:51 +00:00
2023-05-15 15:49:44 +00:00
m_inspect_dom_node_action = make < QAction > ( " &Inspect Element " , this ) ;
connect ( m_inspect_dom_node_action , & QAction : : triggered , this , [ this ] {
2023-05-13 12:07:12 +00:00
if ( m_current_tab )
2023-05-17 15:54:36 +00:00
m_current_tab - > show_inspector_window ( Tab : : InspectorTarget : : HoveredElement ) ;
2023-05-13 12:07:12 +00:00
} ) ;
m_go_back_action = make < QAction > ( " Go Back " ) ;
connect ( m_go_back_action , & QAction : : triggered , this , [ this ] {
if ( m_current_tab )
m_current_tab - > back ( ) ;
} ) ;
m_go_forward_action = make < QAction > ( " Go Forward " ) ;
connect ( m_go_forward_action , & QAction : : triggered , this , [ this ] {
if ( m_current_tab )
m_current_tab - > forward ( ) ;
} ) ;
m_reload_action = make < QAction > ( " &Reload " ) ;
connect ( m_reload_action , & QAction : : triggered , this , [ this ] {
if ( m_current_tab )
m_current_tab - > reload ( ) ;
} ) ;
2023-05-15 15:49:44 +00:00
2023-05-13 12:07:12 +00:00
m_go_back_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Back ) ) ;
m_go_forward_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Forward ) ) ;
m_reload_action - > setShortcuts ( QKeySequence : : keyBindings ( QKeySequence : : StandardKey : : Refresh ) ) ;
m_go_back_action - > setEnabled ( false ) ;
m_go_forward_action - > setEnabled ( false ) ;
2023-03-20 22:39:20 +00:00
new_tab ( s_settings - > new_tab_page ( ) , Web : : HTML : : ActivateTab : : Yes ) ;
2022-07-05 22:18:21 +00:00
setCentralWidget ( m_tabs_container ) ;
2023-05-15 15:49:44 +00:00
setContextMenuPolicy ( Qt : : PreventContextMenu ) ;
2023-05-08 20:15:35 +00:00
}
2023-03-26 17:56:17 +00:00
void BrowserWindow : : set_current_tab ( Tab * tab )
{
m_current_tab = tab ;
2023-03-27 17:29:47 +00:00
if ( tab )
2023-03-28 23:25:42 +00:00
update_displayed_zoom_level ( ) ;
2023-03-26 17:56:17 +00:00
}
2022-12-04 18:43:54 +00:00
void BrowserWindow : : debug_request ( DeprecatedString const & request , DeprecatedString const & argument )
2022-07-08 12:14:40 +00:00
{
if ( ! m_current_tab )
return ;
m_current_tab - > debug_request ( request , argument ) ;
}
2023-03-20 22:39:20 +00:00
Tab & BrowserWindow : : new_tab ( QString const & url , Web : : HTML : : ActivateTab activate_tab )
2022-07-05 22:18:21 +00:00
{
2023-04-15 00:04:28 +00:00
auto tab = make < Tab > ( this , m_webdriver_content_ipc_path , m_enable_callgrind_profiling ) ;
2022-07-05 22:18:21 +00:00
auto tab_ptr = tab . ptr ( ) ;
m_tabs . append ( std : : move ( tab ) ) ;
2022-07-03 19:26:51 +00:00
2022-07-05 22:18:21 +00:00
if ( m_current_tab = = nullptr ) {
2023-03-26 17:56:17 +00:00
set_current_tab ( tab_ptr ) ;
2022-07-05 22:18:21 +00:00
}
2022-07-03 19:26:51 +00:00
2022-07-05 22:18:21 +00:00
m_tabs_container - > addTab ( tab_ptr , " New Tab " ) ;
2023-03-20 22:39:20 +00:00
if ( activate_tab = = Web : : HTML : : ActivateTab : : Yes )
2023-01-08 10:21:55 +00:00
m_tabs_container - > setCurrentWidget ( tab_ptr ) ;
2022-07-05 19:10:50 +00:00
2022-07-05 22:18:21 +00:00
QObject : : connect ( tab_ptr , & Tab : : title_changed , this , & BrowserWindow : : tab_title_changed ) ;
QObject : : connect ( tab_ptr , & Tab : : favicon_changed , this , & BrowserWindow : : tab_favicon_changed ) ;
2022-07-12 09:41:11 +00:00
2023-01-07 16:40:04 +00:00
QObject : : connect ( & tab_ptr - > view ( ) , & WebContentView : : urls_dropped , this , [ this ] ( auto & urls ) {
VERIFY ( urls . size ( ) ) ;
m_current_tab - > navigate ( urls [ 0 ] . toString ( ) ) ;
for ( qsizetype i = 1 ; i < urls . size ( ) ; + + i )
2023-03-20 22:39:20 +00:00
new_tab ( urls [ i ] . toString ( ) , Web : : HTML : : ActivateTab : : No ) ;
2023-01-07 16:40:04 +00:00
} ) ;
2023-03-20 22:39:20 +00:00
tab_ptr - > view ( ) . on_new_tab = [ this ] ( auto activate_tab ) {
auto & tab = new_tab ( " about:blank " , activate_tab ) ;
2023-03-14 14:19:28 +00:00
return tab . view ( ) . handle ( ) ;
} ;
2023-03-23 00:24:15 +00:00
tab_ptr - > view ( ) . on_tab_open_request = [ this ] ( auto url , auto activate_tab ) {
auto & tab = new_tab ( qstring_from_ak_deprecated_string ( url . to_deprecated_string ( ) ) , activate_tab ) ;
return tab . view ( ) . handle ( ) ;
} ;
tab_ptr - > view ( ) . on_link_click = [ this ] ( auto url , auto target , unsigned modifiers ) {
// TODO: maybe activate tabs according to some configuration, this is just normal current browser behavior
if ( modifiers = = Mod_Ctrl ) {
m_current_tab - > view ( ) . on_tab_open_request ( url , Web : : HTML : : ActivateTab : : No ) ;
} else if ( target = = " _blank " ) {
m_current_tab - > view ( ) . on_tab_open_request ( url , Web : : HTML : : ActivateTab : : Yes ) ;
2023-05-15 16:27:10 +00:00
} else {
m_current_tab - > view ( ) . load ( url ) ;
2023-03-23 00:24:15 +00:00
}
} ;
tab_ptr - > view ( ) . on_link_middle_click = [ this ] ( auto url , auto target , unsigned modifiers ) {
m_current_tab - > view ( ) . on_link_click ( url , target , Mod_Ctrl ) ;
( void ) modifiers ;
} ;
2022-11-14 22:23:35 +00:00
tab_ptr - > view ( ) . on_get_all_cookies = [ this ] ( auto const & url ) {
return m_cookie_jar . get_all_cookies ( url ) ;
} ;
tab_ptr - > view ( ) . on_get_named_cookie = [ this ] ( auto const & url , auto const & name ) {
return m_cookie_jar . get_named_cookie ( url , name ) ;
} ;
2022-12-04 18:43:54 +00:00
tab_ptr - > view ( ) . on_get_cookie = [ this ] ( auto & url , auto source ) - > DeprecatedString {
2022-10-11 08:53:28 +00:00
return m_cookie_jar . get_cookie ( url , source ) ;
} ;
tab_ptr - > view ( ) . on_set_cookie = [ this ] ( auto & url , auto & cookie , auto source ) {
m_cookie_jar . set_cookie ( url , cookie , source ) ;
} ;
2022-12-05 15:15:41 +00:00
tab_ptr - > view ( ) . on_update_cookie = [ this ] ( auto const & cookie ) {
m_cookie_jar . update_cookie ( cookie ) ;
2022-11-14 22:23:35 +00:00
} ;
2022-09-12 07:12:04 +00:00
tab_ptr - > focus_location_editor ( ) ;
2023-01-08 14:01:26 +00:00
2023-01-08 10:21:55 +00:00
// We *don't* load the initial page if we are connected to a WebDriver, as the Set URL command may come in very
2023-01-08 14:01:26 +00:00
// quickly, and become replaced by this load.
if ( m_webdriver_content_ipc_path . is_empty ( ) ) {
// We make it HistoryNavigation so that the initial page doesn't get added to the history.
2023-01-08 10:21:55 +00:00
tab_ptr - > navigate ( url , Tab : : LoadType : : HistoryNavigation ) ;
2023-01-08 14:01:26 +00:00
}
2023-03-14 14:19:28 +00:00
return * tab_ptr ;
2022-07-03 19:26:51 +00:00
}
2023-03-20 23:52:00 +00:00
void BrowserWindow : : activate_tab ( int index )
{
m_tabs_container - > setCurrentIndex ( index ) ;
}
2022-07-06 13:36:49 +00:00
void BrowserWindow : : close_tab ( int index )
{
auto * tab = m_tabs_container - > widget ( index ) ;
m_tabs_container - > removeTab ( index ) ;
m_tabs . remove_first_matching ( [ & ] ( auto & entry ) {
return entry = = tab ;
} ) ;
}
2022-07-19 10:16:46 +00:00
void BrowserWindow : : close_current_tab ( )
{
auto count = m_tabs_container - > count ( ) - 1 ;
if ( ! count )
close ( ) ;
else
close_tab ( m_tabs_container - > currentIndex ( ) ) ;
}
2022-07-05 22:18:21 +00:00
int BrowserWindow : : tab_index ( Tab * tab )
2022-07-03 19:26:51 +00:00
{
2022-07-05 22:18:21 +00:00
return m_tabs_container - > indexOf ( tab ) ;
2022-07-03 19:26:51 +00:00
}
2022-07-04 00:11:58 +00:00
2022-07-05 22:18:21 +00:00
void BrowserWindow : : tab_title_changed ( int index , QString const & title )
2022-07-04 00:11:58 +00:00
{
2022-07-05 22:18:21 +00:00
if ( title . isEmpty ( ) ) {
m_tabs_container - > setTabText ( index , " ... " ) ;
2022-11-07 18:01:43 +00:00
if ( m_tabs_container - > currentIndex ( ) = = index )
setWindowTitle ( " Ladybird " ) ;
2022-07-05 22:18:21 +00:00
} else {
m_tabs_container - > setTabText ( index , title ) ;
2022-11-07 18:01:43 +00:00
if ( m_tabs_container - > currentIndex ( ) = = index )
setWindowTitle ( QString ( " %1 - Ladybird " ) . arg ( title ) ) ;
2022-07-05 22:18:21 +00:00
}
2022-07-04 00:11:58 +00:00
}
2022-07-05 04:53:11 +00:00
2022-07-05 22:18:21 +00:00
void BrowserWindow : : tab_favicon_changed ( int index , QIcon icon )
2022-07-05 04:53:11 +00:00
{
2022-07-05 22:18:21 +00:00
m_tabs_container - > setTabIcon ( index , icon ) ;
2022-11-07 18:05:57 +00:00
if ( m_tabs_container - > currentIndex ( ) = = index )
setWindowIcon ( icon ) ;
2022-07-05 04:53:11 +00:00
}
2022-09-12 07:22:43 +00:00
void BrowserWindow : : open_next_tab ( )
{
if ( m_tabs_container - > count ( ) < = 1 )
return ;
auto next_index = m_tabs_container - > currentIndex ( ) + 1 ;
if ( next_index > = m_tabs_container - > count ( ) )
next_index = 0 ;
m_tabs_container - > setCurrentIndex ( next_index ) ;
}
void BrowserWindow : : open_previous_tab ( )
{
if ( m_tabs_container - > count ( ) < = 1 )
return ;
auto next_index = m_tabs_container - > currentIndex ( ) - 1 ;
if ( next_index < 0 )
next_index = m_tabs_container - > count ( ) - 1 ;
m_tabs_container - > setCurrentIndex ( next_index ) ;
}
2022-09-19 08:48:02 +00:00
void BrowserWindow : : enable_auto_color_scheme ( )
{
for ( auto & tab : m_tabs ) {
2023-03-06 16:16:25 +00:00
tab - > view ( ) . set_preferred_color_scheme ( Web : : CSS : : PreferredColorScheme : : Auto ) ;
2022-09-19 08:48:02 +00:00
}
}
void BrowserWindow : : enable_light_color_scheme ( )
{
for ( auto & tab : m_tabs ) {
2023-03-06 16:16:25 +00:00
tab - > view ( ) . set_preferred_color_scheme ( Web : : CSS : : PreferredColorScheme : : Light ) ;
2022-09-19 08:48:02 +00:00
}
}
void BrowserWindow : : enable_dark_color_scheme ( )
{
for ( auto & tab : m_tabs ) {
2023-03-06 16:16:25 +00:00
tab - > view ( ) . set_preferred_color_scheme ( Web : : CSS : : PreferredColorScheme : : Dark ) ;
2022-09-19 08:48:02 +00:00
}
}
2023-01-12 14:39:53 +00:00
void BrowserWindow : : zoom_in ( )
{
2023-03-26 17:56:17 +00:00
if ( ! m_current_tab )
return ;
m_current_tab - > view ( ) . zoom_in ( ) ;
2023-03-28 23:25:42 +00:00
update_displayed_zoom_level ( ) ;
2023-01-12 14:39:53 +00:00
}
void BrowserWindow : : zoom_out ( )
{
2023-03-26 17:56:17 +00:00
if ( ! m_current_tab )
return ;
m_current_tab - > view ( ) . zoom_out ( ) ;
2023-03-28 23:25:42 +00:00
update_displayed_zoom_level ( ) ;
2023-01-12 14:39:53 +00:00
}
void BrowserWindow : : reset_zoom ( )
{
2023-03-26 17:56:17 +00:00
if ( ! m_current_tab )
return ;
m_current_tab - > view ( ) . reset_zoom ( ) ;
2023-03-28 23:25:42 +00:00
update_displayed_zoom_level ( ) ;
2023-01-12 14:39:53 +00:00
}
2023-01-11 19:09:52 +00:00
void BrowserWindow : : select_all ( )
{
2023-04-23 01:57:08 +00:00
if ( ! m_current_tab )
return ;
2023-05-17 15:54:36 +00:00
if ( auto * console = m_current_tab - > console ( ) ; console & & console - > isActiveWindow ( ) )
2023-04-23 01:57:08 +00:00
console - > view ( ) . select_all ( ) ;
else
m_current_tab - > view ( ) . select_all ( ) ;
2023-01-11 19:09:52 +00:00
}
2023-03-28 23:25:42 +00:00
void BrowserWindow : : update_displayed_zoom_level ( )
2023-03-26 17:56:17 +00:00
{
VERIFY ( m_zoom_menu & & m_current_tab ) ;
auto zoom_level_text = MUST ( String : : formatted ( " &Zoom ({}%) " , round_to < int > ( m_current_tab - > view ( ) . zoom_level ( ) * 100 ) ) ) ;
m_zoom_menu - > setTitle ( qstring_from_ak_string ( zoom_level_text ) ) ;
2023-03-28 23:25:42 +00:00
m_current_tab - > update_reset_zoom_button ( ) ;
2023-03-26 17:56:17 +00:00
}
2023-01-11 19:09:52 +00:00
void BrowserWindow : : copy_selected_text ( )
{
2023-04-23 01:57:08 +00:00
if ( ! m_current_tab )
return ;
DeprecatedString text ;
2023-05-17 15:54:36 +00:00
if ( auto * console = m_current_tab - > console ( ) ; console & & console - > isActiveWindow ( ) )
2023-04-23 01:57:08 +00:00
text = console - > view ( ) . selected_text ( ) ;
else
text = m_current_tab - > view ( ) . selected_text ( ) ;
auto * clipboard = QGuiApplication : : clipboard ( ) ;
clipboard - > setText ( qstring_from_ak_deprecated_string ( text ) ) ;
2023-01-11 19:09:52 +00:00
}
2023-02-05 02:26:20 +00:00
2023-03-08 20:57:24 +00:00
void BrowserWindow : : resizeEvent ( QResizeEvent * event )
{
QWidget : : resizeEvent ( event ) ;
for ( auto & tab : m_tabs ) {
tab - > view ( ) . set_window_size ( { frameSize ( ) . width ( ) , frameSize ( ) . height ( ) } ) ;
}
}
void BrowserWindow : : moveEvent ( QMoveEvent * event )
{
QWidget : : moveEvent ( event ) ;
for ( auto & tab : m_tabs ) {
tab - > view ( ) . set_window_position ( { event - > pos ( ) . x ( ) , event - > pos ( ) . y ( ) } ) ;
}
}
2023-02-05 02:26:20 +00:00
bool BrowserWindow : : eventFilter ( QObject * obj , QEvent * event )
{
if ( event - > type ( ) = = QEvent : : MouseButtonRelease ) {
auto const * const mouse_event = static_cast < QMouseEvent * > ( event ) ;
if ( mouse_event - > button ( ) = = Qt : : MouseButton : : MiddleButton ) {
if ( obj = = m_tabs_container ) {
auto const tab_index = m_tabs_container - > tabBar ( ) - > tabAt ( mouse_event - > pos ( ) ) ;
close_tab ( tab_index ) ;
return true ;
}
}
}
return QMainWindow : : eventFilter ( obj , event ) ;
}