2021-05-17 23:15:20 +02:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
2021-07-06 16:50:20 +02:00
* Copyright ( c ) 2021 , Jakob - Niklas See < git @ nwex . de >
2021-10-23 17:35:14 +01:00
* Copyright ( c ) 2021 , Sam Atkins < atkinssj @ serenityos . org >
2022-02-10 12:28:48 -07:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2021-05-17 23:15:20 +02:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "BrowserWindow.h"
# include "BookmarksBarWidget.h"
2021-05-18 17:32:28 +02:00
# include "Browser.h"
# include "ConsoleWidget.h"
2021-05-17 23:15:20 +02:00
# include "CookieJar.h"
2021-05-18 17:32:28 +02:00
# include "InspectorWidget.h"
2021-05-17 23:15:20 +02:00
# include "Tab.h"
# include <Applications/Browser/BrowserWindowGML.h>
2021-08-26 00:18:42 +02:00
# include <LibConfig/Client.h>
2022-01-31 21:55:26 +01:00
# include <LibCore/Process.h>
2021-05-17 23:15:20 +02:00
# include <LibCore/StandardPaths.h>
2022-01-20 11:17:17 +00:00
# include <LibCore/Stream.h>
2021-05-17 23:15:20 +02:00
# include <LibGUI/AboutDialog.h>
2021-05-18 17:32:28 +02:00
# include <LibGUI/Application.h>
2021-07-14 08:33:35 -04:00
# include <LibGUI/Clipboard.h>
2021-05-17 23:15:20 +02:00
# include <LibGUI/Icon.h>
2021-05-18 17:32:28 +02:00
# include <LibGUI/InputBox.h>
# include <LibGUI/Menu.h>
# include <LibGUI/Menubar.h>
2021-05-19 13:31:33 +02:00
# include <LibGUI/MessageBox.h>
2021-05-17 23:15:20 +02:00
# include <LibGUI/SeparatorWidget.h>
2021-05-18 17:32:28 +02:00
# include <LibGUI/Statusbar.h>
2021-05-17 23:15:20 +02:00
# include <LibGUI/TabWidget.h>
2021-05-18 17:32:28 +02:00
# include <LibGUI/ToolbarContainer.h>
2021-05-17 23:15:20 +02:00
# include <LibGUI/Widget.h>
2021-05-18 17:32:28 +02:00
# include <LibJS/Interpreter.h>
2021-10-23 17:35:14 +01:00
# include <LibWeb/CSS/PreferredColorScheme.h>
2021-05-18 17:32:28 +02:00
# include <LibWeb/Dump.h>
2021-09-08 11:27:46 +02:00
# include <LibWeb/Layout/InitialContainingBlock.h>
2021-05-18 17:32:28 +02:00
# include <LibWeb/Loader/ResourceLoader.h>
# include <LibWeb/OutOfProcessWebView.h>
2021-05-17 23:15:20 +02:00
namespace Browser {
static String bookmarks_file_path ( )
{
StringBuilder builder ;
builder . append ( Core : : StandardPaths : : config_directory ( ) ) ;
builder . append ( " /bookmarks.json " ) ;
return builder . to_string ( ) ;
}
2021-11-24 20:35:25 +00:00
static String search_engines_file_path ( )
{
StringBuilder builder ;
builder . append ( Core : : StandardPaths : : config_directory ( ) ) ;
builder . append ( " /SearchEngines.json " ) ;
return builder . to_string ( ) ;
}
2021-05-17 23:15:20 +02:00
BrowserWindow : : BrowserWindow ( CookieJar & cookie_jar , URL url )
: m_cookie_jar ( cookie_jar )
, m_window_actions ( * this )
{
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " ) ;
m_bookmarks_bar = Browser : : BookmarksBarWidget : : construct ( Browser : : bookmarks_file_path ( ) , true ) ;
resize ( 640 , 480 ) ;
set_icon ( app_icon . bitmap_for_size ( 16 ) ) ;
set_title ( " Browser " ) ;
auto & widget = set_main_widget < GUI : : Widget > ( ) ;
widget . load_from_gml ( browser_window_gml ) ;
auto & top_line = * widget . find_descendant_of_type_named < GUI : : HorizontalSeparator > ( " top_line " ) ;
m_tab_widget = * widget . find_descendant_of_type_named < GUI : : TabWidget > ( " tab_widget " ) ;
2021-10-07 02:12:14 -06:00
m_tab_widget - > set_reorder_allowed ( true ) ;
2021-06-19 12:13:10 +02:00
m_tab_widget - > set_close_button_enabled ( true ) ;
2021-05-17 23:15:20 +02:00
m_tab_widget - > on_tab_count_change = [ & top_line ] ( size_t tab_count ) {
top_line . set_visible ( tab_count > 1 ) ;
} ;
m_tab_widget - > on_change = [ this ] ( auto & active_widget ) {
auto & tab = static_cast < Browser : : Tab & > ( active_widget ) ;
set_window_title_for_tab ( tab ) ;
tab . did_become_active ( ) ;
} ;
m_tab_widget - > on_middle_click = [ ] ( auto & clicked_widget ) {
auto & tab = static_cast < Browser : : Tab & > ( clicked_widget ) ;
tab . on_tab_close_request ( tab ) ;
} ;
2021-06-19 12:13:10 +02:00
m_tab_widget - > on_tab_close_click = [ ] ( auto & clicked_widget ) {
auto & tab = static_cast < Browser : : Tab & > ( clicked_widget ) ;
tab . on_tab_close_request ( tab ) ;
} ;
2021-05-17 23:15:20 +02:00
m_tab_widget - > on_context_menu_request = [ ] ( auto & clicked_widget , const GUI : : ContextMenuEvent & context_menu_event ) {
auto & tab = static_cast < Browser : : Tab & > ( clicked_widget ) ;
tab . context_menu_requested ( context_menu_event . screen_position ( ) ) ;
} ;
m_window_actions . on_create_new_tab = [ this ] {
2022-01-31 21:14:19 +01:00
create_new_tab ( Browser : : url_from_user_input ( Browser : : g_home_url ) , true ) ;
2021-05-17 23:15:20 +02:00
} ;
m_window_actions . on_next_tab = [ this ] {
m_tab_widget - > activate_next_tab ( ) ;
} ;
m_window_actions . on_previous_tab = [ this ] {
m_tab_widget - > activate_previous_tab ( ) ;
} ;
m_window_actions . on_about = [ this ] {
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " ) ;
GUI : : AboutDialog : : show ( " Browser " , app_icon . bitmap_for_size ( 32 ) , this ) ;
} ;
m_window_actions . on_show_bookmarks_bar = [ ] ( auto & action ) {
Browser : : BookmarksBarWidget : : the ( ) . set_visible ( action . is_checked ( ) ) ;
2021-11-24 20:04:43 +00:00
Config : : write_bool ( " Browser " , " Preferences " , " ShowBookmarksBar " , action . is_checked ( ) ) ;
2021-05-17 23:15:20 +02:00
} ;
2021-11-24 20:04:43 +00:00
bool show_bookmarks_bar = Config : : read_bool ( " Browser " , " Preferences " , " ShowBookmarksBar " , true ) ;
m_window_actions . show_bookmarks_bar_action ( ) . set_checked ( show_bookmarks_bar ) ;
Browser : : BookmarksBarWidget : : the ( ) . set_visible ( show_bookmarks_bar ) ;
2021-05-17 23:15:20 +02:00
2021-05-18 17:32:28 +02:00
build_menus ( ) ;
2021-05-17 23:15:20 +02:00
create_new_tab ( move ( url ) , true ) ;
}
2021-05-18 17:32:28 +02:00
void BrowserWindow : : build_menus ( )
{
2021-07-21 21:21:03 +02:00
auto & file_menu = add_menu ( " &File " ) ;
2021-05-18 17:32:28 +02:00
file_menu . add_action ( WindowActions : : the ( ) . create_new_tab_action ( ) ) ;
2021-08-03 17:02:10 +02:00
auto close_tab_action = GUI : : CommonActions : : make_close_tab_action ( [ this ] ( auto & ) {
active_tab ( ) . on_tab_close_request ( active_tab ( ) ) ;
} ,
2021-05-18 17:32:28 +02:00
this ) ;
file_menu . add_action ( close_tab_action ) ;
file_menu . add_separator ( ) ;
file_menu . add_action ( GUI : : CommonActions : : make_quit_action ( [ ] ( auto & ) {
GUI : : Application : : the ( ) - > quit ( ) ;
} ) ) ;
2021-07-21 21:21:03 +02:00
auto & view_menu = add_menu ( " &View " ) ;
2021-05-18 17:32:28 +02:00
view_menu . add_action ( WindowActions : : the ( ) . show_bookmarks_bar_action ( ) ) ;
view_menu . add_separator ( ) ;
view_menu . add_action ( GUI : : CommonActions : : make_fullscreen_action (
[ this ] ( auto & ) {
auto & tab = active_tab ( ) ;
set_fullscreen ( ! is_fullscreen ( ) ) ;
auto is_fullscreen = this - > is_fullscreen ( ) ;
tab_widget ( ) . set_bar_visible ( ! is_fullscreen & & tab_widget ( ) . children ( ) . size ( ) > 1 ) ;
tab . m_toolbar_container - > set_visible ( ! is_fullscreen ) ;
tab . m_statusbar - > set_visible ( ! is_fullscreen ) ;
if ( is_fullscreen ) {
tab . view ( ) . set_frame_thickness ( 0 ) ;
} else {
tab . view ( ) . set_frame_thickness ( 2 ) ;
}
} ,
this ) ) ;
2021-05-18 19:23:53 +02:00
m_go_back_action = GUI : : CommonActions : : make_go_back_action ( [ this ] ( auto & ) { active_tab ( ) . go_back ( ) ; } , this ) ;
m_go_forward_action = GUI : : CommonActions : : make_go_forward_action ( [ this ] ( auto & ) { active_tab ( ) . go_forward ( ) ; } , this ) ;
2022-01-31 21:14:19 +01:00
m_go_home_action = GUI : : CommonActions : : make_go_home_action ( [ this ] ( auto & ) { active_tab ( ) . load ( Browser : : url_from_user_input ( g_home_url ) ) ; } , this ) ;
2021-05-18 19:23:53 +02:00
m_go_home_action - > set_status_tip ( " Go to home page " ) ;
m_reload_action = GUI : : CommonActions : : make_reload_action ( [ this ] ( auto & ) { active_tab ( ) . reload ( ) ; } , this ) ;
m_reload_action - > set_status_tip ( " Reload current page " ) ;
2021-05-18 17:32:28 +02:00
2021-07-21 21:21:03 +02:00
auto & go_menu = add_menu ( " &Go " ) ;
2021-05-18 19:23:53 +02:00
go_menu . add_action ( * m_go_back_action ) ;
go_menu . add_action ( * m_go_forward_action ) ;
go_menu . add_action ( * m_go_home_action ) ;
2021-05-18 17:32:28 +02:00
go_menu . add_separator ( ) ;
2021-05-18 19:23:53 +02:00
go_menu . add_action ( * m_reload_action ) ;
2021-05-18 17:32:28 +02:00
2021-07-14 08:33:35 -04:00
m_copy_selection_action = GUI : : CommonActions : : make_copy_action ( [ this ] ( auto & ) {
auto & tab = active_tab ( ) ;
2021-08-24 16:35:46 +02:00
auto selected_text = tab . m_web_content_view - > selected_text ( ) ;
2021-07-14 08:33:35 -04:00
if ( ! selected_text . is_empty ( ) )
GUI : : Clipboard : : the ( ) . set_plain_text ( selected_text ) ;
} ) ;
2021-07-14 08:55:36 -04:00
m_select_all_action = GUI : : CommonActions : : make_select_all_action ( [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > select_all ( ) ;
2021-07-14 08:55:36 -04:00
} ) ;
2021-05-18 19:23:53 +02:00
m_view_source_action = GUI : : Action : : create (
2022-01-10 19:06:11 -08:00
" View &Source " , { Mod_Ctrl , Key_U } , g_icon_bag . code , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > get_source ( ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ;
2021-05-18 19:23:53 +02:00
m_view_source_action - > set_status_tip ( " View source code of the current page " ) ;
2021-05-18 17:32:28 +02:00
2021-05-18 19:23:53 +02:00
m_inspect_dom_tree_action = GUI : : Action : : create (
2022-02-09 13:57:50 -05:00
" Inspect &DOM Tree " , { Mod_None , Key_F12 } , g_icon_bag . dom_tree , [ this ] ( auto & ) {
2021-08-17 17:00:27 +01:00
active_tab ( ) . show_inspector_window ( Tab : : InspectorTarget : : Document ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ;
2021-09-13 20:24:59 +02:00
m_inspect_dom_tree_action - > set_status_tip ( " Open inspector window for this page " ) ;
2021-05-18 17:32:28 +02:00
2021-08-17 17:00:27 +01:00
m_inspect_dom_node_action = GUI : : Action : : create (
2022-01-10 19:06:11 -08:00
" &Inspect Element " , g_icon_bag . inspect , [ this ] ( auto & ) {
2021-08-17 17:00:27 +01:00
active_tab ( ) . show_inspector_window ( Tab : : InspectorTarget : : HoveredElement ) ;
} ,
this ) ;
2021-09-13 20:24:59 +02:00
m_inspect_dom_node_action - > set_status_tip ( " Open inspector for this element " ) ;
2021-08-17 17:00:27 +01:00
2021-07-21 21:21:03 +02:00
auto & inspect_menu = add_menu ( " &Inspect " ) ;
2021-05-18 19:23:53 +02:00
inspect_menu . add_action ( * m_view_source_action ) ;
inspect_menu . add_action ( * m_inspect_dom_tree_action ) ;
2021-05-18 17:32:28 +02:00
auto js_console_action = GUI : : Action : : create (
2022-01-10 19:06:11 -08:00
" Open &JS Console " , { Mod_Ctrl , Key_I } , g_icon_bag . filetype_javascript , [ this ] ( auto & ) {
2021-09-01 17:03:18 +01:00
active_tab ( ) . show_console_window ( ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ;
js_console_action - > set_status_tip ( " Open JavaScript console for this page " ) ;
inspect_menu . add_action ( js_console_action ) ;
2021-07-21 21:21:03 +02:00
auto & settings_menu = add_menu ( " &Settings " ) ;
2021-05-18 17:32:28 +02:00
2021-06-15 22:49:34 +02:00
m_change_homepage_action = GUI : : Action : : create (
2022-02-06 21:33:20 -05:00
" Set Homepage URL... " , g_icon_bag . go_home , [ this ] ( auto & ) {
2021-08-26 00:18:42 +02:00
auto homepage_url = Config : : read_string ( " Browser " , " Preferences " , " Home " , " about:blank " ) ;
2021-06-15 22:49:34 +02:00
if ( GUI : : InputBox : : show ( this , homepage_url , " Enter URL " , " Change homepage URL " ) = = GUI : : InputBox : : ExecOK ) {
if ( URL ( homepage_url ) . is_valid ( ) ) {
2021-08-26 00:18:42 +02:00
Config : : write_string ( " Browser " , " Preferences " , " Home " , homepage_url ) ;
2021-06-15 22:49:34 +02:00
Browser : : g_home_url = homepage_url ;
} else {
GUI : : MessageBox : : show_error ( this , " The URL you have entered is not valid " ) ;
}
}
} ,
this ) ;
settings_menu . add_action ( * m_change_homepage_action ) ;
2022-01-20 11:17:17 +00:00
auto load_search_engines_result = load_search_engines ( settings_menu ) ;
if ( load_search_engines_result . is_error ( ) ) {
dbgln ( " Failed to open search-engines file: {} " , load_search_engines_result . error ( ) ) ;
2021-05-19 13:31:33 +02:00
}
2021-10-23 17:35:14 +01:00
auto & color_scheme_menu = settings_menu . add_submenu ( " &Color Scheme " ) ;
2022-01-10 19:06:11 -08:00
color_scheme_menu . set_icon ( g_icon_bag . color_chooser ) ;
2021-10-23 17:35:14 +01:00
{
auto current_setting = Web : : CSS : : preferred_color_scheme_from_string ( Config : : read_string ( " Browser " , " Preferences " , " ColorScheme " , " auto " ) ) ;
m_color_scheme_actions . set_exclusive ( true ) ;
auto add_color_scheme_action = [ & ] ( auto & name , Web : : CSS : : PreferredColorScheme preference_value ) {
auto action = GUI : : Action : : create_checkable (
name , [ = , this ] ( auto & ) {
Config : : write_string ( " Browser " , " Preferences " , " ColorScheme " , Web : : CSS : : preferred_color_scheme_to_string ( preference_value ) ) ;
active_tab ( ) . m_web_content_view - > set_preferred_color_scheme ( preference_value ) ;
} ,
this ) ;
if ( current_setting = = preference_value )
action - > set_checked ( true ) ;
color_scheme_menu . add_action ( action ) ;
m_color_scheme_actions . add_action ( action ) ;
} ;
add_color_scheme_action ( " Follow system theme " , Web : : CSS : : PreferredColorScheme : : Auto ) ;
add_color_scheme_action ( " Light " , Web : : CSS : : PreferredColorScheme : : Light ) ;
add_color_scheme_action ( " Dark " , Web : : CSS : : PreferredColorScheme : : Dark ) ;
}
2022-01-31 21:55:26 +01:00
settings_menu . add_separator ( ) ;
auto open_settings_action = GUI : : Action : : create ( " &Settings... " , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/settings.png " ) . release_value_but_fixme_should_propagate_errors ( ) ,
[ ] ( auto & ) {
Core : : Process : : spawn ( " /bin/BrowserSettings " ) ;
} ) ;
settings_menu . add_action ( move ( open_settings_action ) ) ;
2021-07-21 21:21:03 +02:00
auto & debug_menu = add_menu ( " &Debug " ) ;
2021-05-18 17:32:28 +02:00
debug_menu . add_action ( GUI : : Action : : create (
2022-02-09 13:57:50 -05:00
" Dump &DOM Tree " , g_icon_bag . dom_tree , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " dump-dom-tree " ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-06 21:33:20 -05:00
" Dump &Layout Tree " , g_icon_bag . layout , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " dump-layout-tree " ) ;
2022-02-05 19:01:12 +01:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-09 01:21:10 +01:00
" Dump S&tacking Context Tree " , g_icon_bag . layers , [ this ] ( auto & ) {
2022-02-05 19:01:12 +01:00
active_tab ( ) . m_web_content_view - > debug_request ( " dump-stacking-context-tree " ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-09 13:57:50 -05:00
" Dump &Style Sheets " , g_icon_bag . filetype_css , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " dump-style-sheets " ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ) ;
2022-02-06 21:33:20 -05:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump &History " , { Mod_Ctrl , Key_H } , g_icon_bag . history , [ this ] ( auto & ) {
2021-05-18 17:32:28 +02:00
active_tab ( ) . m_history . dump ( ) ;
} ) ) ;
2022-01-10 19:06:11 -08:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump C&ookies " , g_icon_bag . cookie , [ this ] ( auto & ) {
2021-05-18 17:32:28 +02:00
auto & tab = active_tab ( ) ;
if ( tab . on_dump_cookies )
tab . on_dump_cookies ( ) ;
} ) ) ;
2022-02-09 13:57:50 -05:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump Loc&al Storage " , g_icon_bag . local_storage , [ this ] ( auto & ) {
2022-02-08 19:50:14 +01:00
active_tab ( ) . m_web_content_view - > debug_request ( " dump-local-storage " ) ;
} ) ) ;
2021-05-18 17:32:28 +02:00
debug_menu . add_separator ( ) ;
auto line_box_borders_action = GUI : : Action : : create_checkable (
2021-05-21 18:51:06 +02:00
" Line &Box Borders " , [ this ] ( auto & action ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " set-line-box-borders " , action . is_checked ( ) ? " on " : " off " ) ;
2021-05-18 17:32:28 +02:00
} ,
this ) ;
line_box_borders_action - > set_checked ( false ) ;
debug_menu . add_action ( line_box_borders_action ) ;
debug_menu . add_separator ( ) ;
2022-02-06 21:33:20 -05:00
debug_menu . add_action ( GUI : : Action : : create ( " Collect &Garbage " , { Mod_Ctrl | Mod_Shift , Key_G } , g_icon_bag . trash_can , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " collect-garbage " ) ;
2021-05-18 17:32:28 +02:00
} ) ) ;
2022-02-06 21:33:20 -05:00
debug_menu . add_action ( GUI : : Action : : create ( " Clear &Cache " , { Mod_Ctrl | Mod_Shift , Key_C } , g_icon_bag . clear_cache , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " clear-cache " ) ;
2021-05-18 17:32:28 +02:00
} ) ) ;
m_user_agent_spoof_actions . set_exclusive ( true ) ;
2021-05-21 18:51:06 +02:00
auto & spoof_user_agent_menu = debug_menu . add_submenu ( " Spoof &User Agent " ) ;
2021-05-18 17:32:28 +02:00
m_disable_user_agent_spoofing = GUI : : Action : : create_checkable ( " Disabled " , [ this ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " spoof-user-agent " , Web : : default_user_agent ) ;
2021-05-18 17:32:28 +02:00
} ) ;
m_disable_user_agent_spoofing - > set_status_tip ( Web : : default_user_agent ) ;
spoof_user_agent_menu . add_action ( * m_disable_user_agent_spoofing ) ;
2022-02-06 21:33:20 -05:00
spoof_user_agent_menu . set_icon ( g_icon_bag . spoof ) ;
2021-05-18 17:32:28 +02:00
m_user_agent_spoof_actions . add_action ( * m_disable_user_agent_spoofing ) ;
m_disable_user_agent_spoofing - > set_checked ( true ) ;
auto add_user_agent = [ this , & spoof_user_agent_menu ] ( auto & name , auto & user_agent ) {
auto action = GUI : : Action : : create_checkable ( name , [ this , user_agent ] ( auto & ) {
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " spoof-user-agent " , user_agent ) ;
2021-05-18 17:32:28 +02:00
} ) ;
action - > set_status_tip ( user_agent ) ;
spoof_user_agent_menu . add_action ( action ) ;
m_user_agent_spoof_actions . add_action ( action ) ;
} ;
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 " ) ;
2021-07-30 14:57:20 +02:00
auto custom_user_agent = GUI : : Action : : create_checkable ( " Custom... " , [ this ] ( auto & action ) {
2021-05-18 17:32:28 +02:00
String user_agent ;
if ( GUI : : InputBox : : show ( this , user_agent , " Enter User Agent: " , " Custom User Agent " ) ! = GUI : : InputBox : : ExecOK | | user_agent . is_empty ( ) | | user_agent . is_null ( ) ) {
m_disable_user_agent_spoofing - > activate ( ) ;
return ;
}
2021-08-24 16:35:46 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " spoof-user-agent " , user_agent ) ;
2021-05-18 17:32:28 +02:00
action . set_status_tip ( user_agent ) ;
} ) ;
spoof_user_agent_menu . add_action ( custom_user_agent ) ;
m_user_agent_spoof_actions . add_action ( custom_user_agent ) ;
2021-09-12 02:10:43 +02:00
debug_menu . add_separator ( ) ;
auto same_origin_policy_action = GUI : : Action : : create_checkable (
2022-02-09 01:21:10 +01:00
" Enable Same Origin &Policy " , [ this ] ( auto & action ) {
2021-09-12 02:10:43 +02:00
active_tab ( ) . m_web_content_view - > debug_request ( " same-origin-policy " , action . is_checked ( ) ? " on " : " off " ) ;
} ,
this ) ;
2021-10-03 23:39:07 +02:00
same_origin_policy_action - > set_checked ( false ) ;
2021-09-12 02:10:43 +02:00
debug_menu . add_action ( same_origin_policy_action ) ;
2021-07-21 21:21:03 +02:00
auto & help_menu = add_menu ( " &Help " ) ;
2021-05-18 17:32:28 +02:00
help_menu . add_action ( WindowActions : : the ( ) . about_action ( ) ) ;
}
2022-01-20 11:17:17 +00:00
ErrorOr < void > BrowserWindow : : load_search_engines ( GUI : : Menu & settings_menu )
{
m_search_engine_actions . set_exclusive ( true ) ;
auto & search_engine_menu = settings_menu . add_submenu ( " &Search Engine " ) ;
search_engine_menu . set_icon ( g_icon_bag . find ) ;
bool search_engine_set = false ;
m_disable_search_engine_action = GUI : : Action : : create_checkable (
" Disable " , [ ] ( auto & ) {
g_search_engine = { } ;
Config : : write_string ( " Browser " , " Preferences " , " SearchEngine " , g_search_engine ) ;
} ,
this ) ;
search_engine_menu . add_action ( * m_disable_search_engine_action ) ;
m_search_engine_actions . add_action ( * m_disable_search_engine_action ) ;
m_disable_search_engine_action - > set_checked ( true ) ;
auto search_engines_file = TRY ( Core : : Stream : : File : : open ( Browser : : search_engines_file_path ( ) , Core : : Stream : : OpenMode : : Read ) ) ;
auto file_size = TRY ( search_engines_file - > size ( ) ) ;
2022-01-20 17:47:39 +00:00
auto buffer = TRY ( ByteBuffer : : create_uninitialized ( file_size ) ) ;
2022-01-20 11:17:17 +00:00
if ( search_engines_file - > read_or_error ( buffer ) ) {
StringView buffer_contents { buffer . bytes ( ) } ;
if ( auto json = TRY ( JsonValue : : from_string ( buffer_contents ) ) ; json . is_array ( ) ) {
auto json_array = json . as_array ( ) ;
for ( auto & json_item : json_array . values ( ) ) {
if ( ! json_item . is_object ( ) )
continue ;
auto search_engine = json_item . as_object ( ) ;
auto name = search_engine . get ( " title " ) . to_string ( ) ;
auto url_format = search_engine . get ( " url_format " ) . to_string ( ) ;
auto action = GUI : : Action : : create_checkable (
name , [ & , url_format ] ( auto & ) {
g_search_engine = url_format ;
Config : : write_string ( " Browser " , " Preferences " , " SearchEngine " , g_search_engine ) ;
} ,
this ) ;
search_engine_menu . add_action ( action ) ;
m_search_engine_actions . add_action ( action ) ;
if ( g_search_engine = = url_format ) {
action - > set_checked ( true ) ;
search_engine_set = true ;
}
action - > set_status_tip ( url_format ) ;
}
}
}
auto custom_search_engine_action = GUI : : Action : : create_checkable ( " Custom... " , [ & ] ( auto & action ) {
String search_engine ;
if ( GUI : : InputBox : : show ( this , search_engine , " Enter URL template: " , " Custom Search Engine " , " https://host/search?q={} " ) ! = GUI : : InputBox : : ExecOK | | search_engine . is_empty ( ) ) {
m_disable_search_engine_action - > activate ( ) ;
return ;
}
auto argument_count = search_engine . count ( " {} " sv ) ;
if ( argument_count ! = 1 ) {
GUI : : MessageBox : : show ( this , " Invalid format, must contain '{}' once! " , " Error " , GUI : : MessageBox : : Type : : Error ) ;
m_disable_search_engine_action - > activate ( ) ;
return ;
}
g_search_engine = search_engine ;
Config : : write_string ( " Browser " , " Preferences " , " SearchEngine " , g_search_engine ) ;
action . set_status_tip ( search_engine ) ;
} ) ;
search_engine_menu . add_action ( custom_search_engine_action ) ;
m_search_engine_actions . add_action ( custom_search_engine_action ) ;
if ( ! search_engine_set & & ! g_search_engine . is_empty ( ) ) {
custom_search_engine_action - > set_checked ( true ) ;
custom_search_engine_action - > set_status_tip ( g_search_engine ) ;
}
return { } ;
}
2021-05-17 23:15:20 +02:00
GUI : : TabWidget & BrowserWindow : : tab_widget ( )
{
return * m_tab_widget ;
}
2021-05-18 17:32:28 +02:00
Tab & BrowserWindow : : active_tab ( )
{
2021-06-24 19:53:42 +02:00
return verify_cast < Tab > ( * tab_widget ( ) . active_widget ( ) ) ;
2021-05-18 17:32:28 +02:00
}
2021-05-17 23:15:20 +02:00
void BrowserWindow : : set_window_title_for_tab ( Tab const & tab )
{
auto & title = tab . title ( ) ;
auto url = tab . url ( ) ;
set_title ( String : : formatted ( " {} - Browser " , title . is_empty ( ) ? url . to_string ( ) : title ) ) ;
}
void BrowserWindow : : create_new_tab ( URL url , bool activate )
{
2021-08-24 16:35:46 +02:00
auto & new_tab = m_tab_widget - > add_tab < Browser : : Tab > ( " New tab " , * this ) ;
2021-05-17 23:15:20 +02:00
m_tab_widget - > set_bar_visible ( ! is_fullscreen ( ) & & m_tab_widget - > children ( ) . size ( ) > 1 ) ;
2021-05-29 01:14:04 +01:00
new_tab . on_title_change = [ this , & new_tab ] ( auto & title ) {
2021-05-17 23:15:20 +02:00
m_tab_widget - > set_tab_title ( new_tab , title ) ;
if ( m_tab_widget - > active_widget ( ) = = & new_tab )
set_window_title_for_tab ( new_tab ) ;
} ;
new_tab . on_favicon_change = [ this , & new_tab ] ( auto & bitmap ) {
m_tab_widget - > set_tab_icon ( new_tab , & bitmap ) ;
} ;
new_tab . on_tab_open_request = [ this ] ( auto & url ) {
create_new_tab ( url , true ) ;
} ;
new_tab . on_tab_close_request = [ this ] ( auto & tab ) {
2021-08-30 18:12:48 +00:00
m_tab_widget - > deferred_invoke ( [ this , & tab ] {
2021-05-17 23:15:20 +02:00
m_tab_widget - > remove_tab ( tab ) ;
m_tab_widget - > set_bar_visible ( ! is_fullscreen ( ) & & m_tab_widget - > children ( ) . size ( ) > 1 ) ;
if ( m_tab_widget - > children ( ) . is_empty ( ) )
close ( ) ;
} ) ;
} ;
2021-08-07 00:21:14 +08:00
new_tab . on_tab_close_other_request = [ this ] ( auto & tab ) {
2021-08-30 18:12:48 +00:00
m_tab_widget - > deferred_invoke ( [ this , & tab ] {
2021-08-07 00:21:14 +08:00
m_tab_widget - > remove_all_tabs_except ( tab ) ;
VERIFY ( m_tab_widget - > children ( ) . size ( ) = = 1 ) ;
m_tab_widget - > set_bar_visible ( false ) ;
} ) ;
} ;
2021-05-17 23:15:20 +02:00
new_tab . on_get_cookie = [ this ] ( auto & url , auto source ) - > String {
return m_cookie_jar . get_cookie ( url , source ) ;
} ;
new_tab . on_set_cookie = [ this ] ( auto & url , auto & cookie , auto source ) {
m_cookie_jar . set_cookie ( url , cookie , source ) ;
} ;
new_tab . on_dump_cookies = [ this ] ( ) {
m_cookie_jar . dump_cookies ( ) ;
} ;
new_tab . load ( url ) ;
2021-08-07 16:37:26 +08:00
dbgln_if ( SPAM_DEBUG , " Added new tab {:p}, loading {} " , & new_tab , url ) ;
2021-05-17 23:15:20 +02:00
if ( activate )
m_tab_widget - > set_active_widget ( & new_tab ) ;
}
2022-02-01 11:17:37 +01:00
void BrowserWindow : : content_filters_changed ( )
{
tab_widget ( ) . for_each_child_of_type < Browser : : Tab > ( [ ] ( auto & tab ) {
tab . content_filters_changed ( ) ;
return IterationDecision : : Continue ;
} ) ;
}
2022-01-31 21:40:48 +01:00
void BrowserWindow : : config_string_did_change ( String const & domain , String const & group , String const & key , String const & value )
{
if ( domain ! = " Browser " | | group ! = " Preferences " )
return ;
if ( key = = " SearchEngine " )
Browser : : g_search_engine = value ;
else if ( key = = " Home " )
Browser : : g_home_url = value ;
2022-01-31 21:55:26 +01:00
// TODO: ColorScheme
2022-01-31 21:40:48 +01:00
}
void BrowserWindow : : config_bool_did_change ( String const & domain , String const & group , String const & key , bool value )
{
2022-02-01 11:17:37 +01:00
dbgln ( " {} {} {} {} " , domain , group , key , value ) ;
2022-01-31 21:40:48 +01:00
if ( domain ! = " Browser " | | group ! = " Preferences " )
return ;
if ( key = = " ShowBookmarksBar " ) {
m_window_actions . show_bookmarks_bar_action ( ) . set_checked ( value ) ;
Browser : : BookmarksBarWidget : : the ( ) . set_visible ( value ) ;
2022-02-01 11:17:37 +01:00
} else if ( key = = " EnableContentFilters " ) {
Browser : : g_content_filters_enabled = value ;
content_filters_changed ( ) ;
2022-01-31 21:40:48 +01:00
}
// NOTE: CloseDownloadWidgetOnFinish is read each time in DownloadWindow
}
2021-05-17 23:15:20 +02:00
}