2021-05-17 18:15:20 -03:00
/*
* Copyright ( c ) 2021 , Andreas Kling < kling @ serenityos . org >
2022-09-12 11:06:24 -03:00
* Copyright ( c ) 2021 , networkException < networkexception @ serenityos . org >
2021-10-23 13:35:14 -03:00
* Copyright ( c ) 2021 , Sam Atkins < atkinssj @ serenityos . org >
2022-02-10 16:28:48 -03:00
* Copyright ( c ) 2022 , the SerenityOS developers .
2021-05-17 18:15:20 -03:00
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "BrowserWindow.h"
# include "BookmarksBarWidget.h"
2021-05-18 12:32:28 -03:00
# include "Browser.h"
# include "ConsoleWidget.h"
2021-05-17 18:15:20 -03:00
# include "CookieJar.h"
2021-05-18 12:32:28 -03:00
# include "InspectorWidget.h"
2021-05-17 18:15:20 -03:00
# include "Tab.h"
# include <Applications/Browser/BrowserWindowGML.h>
2021-08-25 19:18:42 -03:00
# include <LibConfig/Client.h>
2021-05-17 18:15:20 -03:00
# include <LibCore/StandardPaths.h>
2022-01-20 08:17:17 -03:00
# include <LibCore/Stream.h>
2021-05-17 18:15:20 -03:00
# include <LibGUI/AboutDialog.h>
2021-05-18 12:32:28 -03:00
# include <LibGUI/Application.h>
2021-07-14 09:33:35 -03:00
# include <LibGUI/Clipboard.h>
2021-05-17 18:15:20 -03:00
# include <LibGUI/Icon.h>
2021-05-18 12:32:28 -03:00
# include <LibGUI/InputBox.h>
# include <LibGUI/Menu.h>
# include <LibGUI/Menubar.h>
2021-05-19 08:31:33 -03:00
# include <LibGUI/MessageBox.h>
2022-05-11 15:41:33 -03:00
# include <LibGUI/Process.h>
2021-05-17 18:15:20 -03:00
# include <LibGUI/SeparatorWidget.h>
2021-05-18 12:32:28 -03:00
# include <LibGUI/Statusbar.h>
2021-05-17 18:15:20 -03:00
# include <LibGUI/TabWidget.h>
2021-05-18 12:32:28 -03:00
# include <LibGUI/ToolbarContainer.h>
2021-05-17 18:15:20 -03:00
# include <LibGUI/Widget.h>
2021-05-18 12:32:28 -03:00
# include <LibJS/Interpreter.h>
2021-10-23 13:35:14 -03:00
# include <LibWeb/CSS/PreferredColorScheme.h>
2021-05-18 12:32:28 -03:00
# include <LibWeb/Dump.h>
2021-09-08 06:27:46 -03:00
# include <LibWeb/Layout/InitialContainingBlock.h>
2021-05-18 12:32:28 -03:00
# include <LibWeb/Loader/ResourceLoader.h>
2022-04-30 05:46:33 -03:00
# include <LibWebView/OutOfProcessWebView.h>
2021-05-17 18:15:20 -03:00
namespace Browser {
static String bookmarks_file_path ( )
{
StringBuilder builder ;
builder . append ( Core : : StandardPaths : : config_directory ( ) ) ;
2022-07-11 14:32:29 -03:00
builder . append ( " /bookmarks.json " sv ) ;
2021-05-17 18:15:20 -03:00
return builder . to_string ( ) ;
}
2021-11-24 17:35:25 -03:00
static String search_engines_file_path ( )
{
StringBuilder builder ;
builder . append ( Core : : StandardPaths : : config_directory ( ) ) ;
2022-07-11 14:32:29 -03:00
builder . append ( " /SearchEngines.json " sv ) ;
2021-11-24 17:35:25 -03:00
return builder . to_string ( ) ;
}
2021-05-17 18:15:20 -03:00
BrowserWindow : : BrowserWindow ( CookieJar & cookie_jar , URL url )
: m_cookie_jar ( cookie_jar )
, m_window_actions ( * this )
{
2022-07-11 14:32:29 -03:00
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " sv ) ;
2021-05-17 18:15:20 -03:00
m_bookmarks_bar = Browser : : BookmarksBarWidget : : construct ( Browser : : bookmarks_file_path ( ) , true ) ;
2022-03-26 16:49:42 -03:00
resize ( 730 , 560 ) ;
2021-05-17 18:15:20 -03:00
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 " ) ;
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 07:13:10 -03: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 18:15:20 -03: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-06-25 16:08:17 -03:00
create_new_tab ( Browser : : url_from_user_input ( Browser : : g_new_tab_url ) , true ) ;
2021-05-17 18:15:20 -03: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 ( ) ;
} ;
2022-06-05 08:08:09 -03:00
for ( size_t i = 0 ; i < = 7 ; + + i ) {
2022-03-16 16:10:00 -03:00
m_window_actions . on_tabs . append ( [ this , i ] {
2022-06-05 08:08:09 -03:00
if ( i > = m_tab_widget - > tab_count ( ) )
return ;
2022-03-16 16:10:00 -03:00
m_tab_widget - > set_tab_index ( i ) ;
} ) ;
}
m_window_actions . on_tabs . append ( [ this ] {
m_tab_widget - > activate_last_tab ( ) ;
} ) ;
2021-05-17 18:15:20 -03:00
m_window_actions . on_about = [ this ] {
2022-07-11 14:32:29 -03:00
auto app_icon = GUI : : Icon : : default_icon ( " app-browser " sv ) ;
GUI : : AboutDialog : : show ( " Browser " sv , app_icon . bitmap_for_size ( 32 ) , this ) ;
2021-05-17 18:15:20 -03:00
} ;
m_window_actions . on_show_bookmarks_bar = [ ] ( auto & action ) {
Browser : : BookmarksBarWidget : : the ( ) . set_visible ( action . is_checked ( ) ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " Browser " sv , " Preferences " sv , " ShowBookmarksBar " sv , action . is_checked ( ) ) ;
2021-05-17 18:15:20 -03:00
} ;
2022-07-11 14:32:29 -03:00
bool show_bookmarks_bar = Config : : read_bool ( " Browser " sv , " Preferences " sv , " ShowBookmarksBar " sv , true ) ;
2021-11-24 17:04:43 -03:00
m_window_actions . show_bookmarks_bar_action ( ) . set_checked ( show_bookmarks_bar ) ;
Browser : : BookmarksBarWidget : : the ( ) . set_visible ( show_bookmarks_bar ) ;
2021-05-17 18:15:20 -03:00
2022-05-13 05:42:44 -03:00
m_window_actions . on_vertical_tabs = [ this ] ( auto & action ) {
m_tab_widget - > set_tab_position ( action . is_checked ( ) ? GUI : : TabWidget : : TabPosition : : Left : GUI : : TabWidget : : TabPosition : : Top ) ;
2022-07-11 14:32:29 -03:00
Config : : write_bool ( " Browser " sv , " Preferences " sv , " VerticalTabs " sv , action . is_checked ( ) ) ;
2022-05-13 05:42:44 -03:00
} ;
2022-07-11 14:32:29 -03:00
bool vertical_tabs = Config : : read_bool ( " Browser " sv , " Preferences " sv , " VerticalTabs " sv , false ) ;
2022-05-13 05:42:44 -03:00
m_window_actions . vertical_tabs_action ( ) . set_checked ( vertical_tabs ) ;
m_tab_widget - > set_tab_position ( vertical_tabs ? GUI : : TabWidget : : TabPosition : : Left : GUI : : TabWidget : : TabPosition : : Top ) ;
2021-05-18 12:32:28 -03:00
build_menus ( ) ;
2021-05-17 18:15:20 -03:00
create_new_tab ( move ( url ) , true ) ;
}
2021-05-18 12:32:28 -03:00
void BrowserWindow : : build_menus ( )
{
2021-07-21 16:21:03 -03:00
auto & file_menu = add_menu ( " &File " ) ;
2021-05-18 12:32:28 -03:00
file_menu . add_action ( WindowActions : : the ( ) . create_new_tab_action ( ) ) ;
2021-08-03 12:02:10 -03:00
auto close_tab_action = GUI : : CommonActions : : make_close_tab_action ( [ this ] ( auto & ) {
active_tab ( ) . on_tab_close_request ( active_tab ( ) ) ;
} ,
2021-05-18 12:32:28 -03: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 16:21:03 -03:00
auto & view_menu = add_menu ( " &View " ) ;
2021-05-18 12:32:28 -03:00
view_menu . add_action ( WindowActions : : the ( ) . show_bookmarks_bar_action ( ) ) ;
2022-05-13 05:42:44 -03:00
view_menu . add_action ( WindowActions : : the ( ) . vertical_tabs_action ( ) ) ;
2021-05-18 12:32:28 -03:00
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 14:23:53 -03: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 17:14:19 -03: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 14:23:53 -03: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 12:32:28 -03:00
2021-07-21 16:21:03 -03:00
auto & go_menu = add_menu ( " &Go " ) ;
2021-05-18 14:23:53 -03: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 12:32:28 -03:00
go_menu . add_separator ( ) ;
2021-05-18 14:23:53 -03:00
go_menu . add_action ( * m_reload_action ) ;
2021-05-18 12:32:28 -03:00
2021-07-14 09:33:35 -03:00
m_copy_selection_action = GUI : : CommonActions : : make_copy_action ( [ this ] ( auto & ) {
auto & tab = active_tab ( ) ;
2022-04-06 10:15:07 -03:00
auto selected_text = tab . view ( ) . selected_text ( ) ;
2021-07-14 09:33:35 -03:00
if ( ! selected_text . is_empty ( ) )
GUI : : Clipboard : : the ( ) . set_plain_text ( selected_text ) ;
} ) ;
2021-07-14 09:55:36 -03:00
m_select_all_action = GUI : : CommonActions : : make_select_all_action ( [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . select_all ( ) ;
2021-07-14 09:55:36 -03:00
} ) ;
2021-05-18 14:23:53 -03:00
m_view_source_action = GUI : : Action : : create (
2022-01-11 00:06:11 -03:00
" View &Source " , { Mod_Ctrl , Key_U } , g_icon_bag . code , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . get_source ( ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ;
2021-05-18 14:23:53 -03:00
m_view_source_action - > set_status_tip ( " View source code of the current page " ) ;
2021-05-18 12:32:28 -03:00
2021-05-18 14:23:53 -03:00
m_inspect_dom_tree_action = GUI : : Action : : create (
2022-02-09 15:57:50 -03:00
" Inspect &DOM Tree " , { Mod_None , Key_F12 } , g_icon_bag . dom_tree , [ this ] ( auto & ) {
2021-08-17 13:00:27 -03:00
active_tab ( ) . show_inspector_window ( Tab : : InspectorTarget : : Document ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ;
2021-09-13 15:24:59 -03:00
m_inspect_dom_tree_action - > set_status_tip ( " Open inspector window for this page " ) ;
2021-05-18 12:32:28 -03:00
2021-08-17 13:00:27 -03:00
m_inspect_dom_node_action = GUI : : Action : : create (
2022-01-11 00:06:11 -03:00
" &Inspect Element " , g_icon_bag . inspect , [ this ] ( auto & ) {
2021-08-17 13:00:27 -03:00
active_tab ( ) . show_inspector_window ( Tab : : InspectorTarget : : HoveredElement ) ;
} ,
this ) ;
2021-09-13 15:24:59 -03:00
m_inspect_dom_node_action - > set_status_tip ( " Open inspector for this element " ) ;
2021-08-17 13:00:27 -03:00
2021-07-21 16:21:03 -03:00
auto & inspect_menu = add_menu ( " &Inspect " ) ;
2021-05-18 14:23:53 -03:00
inspect_menu . add_action ( * m_view_source_action ) ;
inspect_menu . add_action ( * m_inspect_dom_tree_action ) ;
2021-05-18 12:32:28 -03:00
auto js_console_action = GUI : : Action : : create (
2022-01-11 00:06:11 -03:00
" Open &JS Console " , { Mod_Ctrl , Key_I } , g_icon_bag . filetype_javascript , [ this ] ( auto & ) {
2021-09-01 13:03:18 -03:00
active_tab ( ) . show_console_window ( ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ;
js_console_action - > set_status_tip ( " Open JavaScript console for this page " ) ;
inspect_menu . add_action ( js_console_action ) ;
2022-03-01 13:11:03 -03:00
auto storage_window_action = GUI : : Action : : create (
" Open S&torage Inspector " , g_icon_bag . cookie , [ this ] ( auto & ) {
active_tab ( ) . show_storage_inspector ( ) ;
} ,
this ) ;
storage_window_action - > set_status_tip ( " Show Storage inspector for this page " ) ;
inspect_menu . add_action ( storage_window_action ) ;
2021-07-21 16:21:03 -03:00
auto & settings_menu = add_menu ( " &Settings " ) ;
2021-05-18 12:32:28 -03:00
2021-06-15 17:49:34 -03:00
m_change_homepage_action = GUI : : Action : : create (
2022-02-06 23:33:20 -03:00
" Set Homepage URL... " , g_icon_bag . go_home , [ this ] ( auto & ) {
2022-07-11 14:32:29 -03:00
auto homepage_url = Config : : read_string ( " Browser " sv , " Preferences " sv , " Home " sv , " about:blank " sv ) ;
if ( GUI : : InputBox : : show ( this , homepage_url , " Enter URL " sv , " Change homepage URL " sv ) = = GUI : : InputBox : : ExecResult : : OK ) {
2021-06-15 17:49:34 -03:00
if ( URL ( homepage_url ) . is_valid ( ) ) {
2022-07-11 14:32:29 -03:00
Config : : write_string ( " Browser " sv , " Preferences " sv , " Home " sv , homepage_url ) ;
2021-06-15 17:49:34 -03:00
Browser : : g_home_url = homepage_url ;
} else {
2022-07-11 14:32:29 -03:00
GUI : : MessageBox : : show_error ( this , " The URL you have entered is not valid " sv ) ;
2021-06-15 17:49:34 -03:00
}
}
} ,
this ) ;
settings_menu . add_action ( * m_change_homepage_action ) ;
2022-01-20 08:17:17 -03: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 08:31:33 -03:00
}
2021-10-23 13:35:14 -03:00
auto & color_scheme_menu = settings_menu . add_submenu ( " &Color Scheme " ) ;
2022-01-11 00:06:11 -03:00
color_scheme_menu . set_icon ( g_icon_bag . color_chooser ) ;
2021-10-23 13:35:14 -03:00
{
2022-07-11 14:32:29 -03:00
auto current_setting = Web : : CSS : : preferred_color_scheme_from_string ( Config : : read_string ( " Browser " sv , " Preferences " sv , " ColorScheme " sv , " auto " sv ) ) ;
2021-10-23 13:35:14 -03:00
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 & ) {
2022-07-11 14:32:29 -03:00
Config : : write_string ( " Browser " sv , " Preferences " sv , " ColorScheme " sv , Web : : CSS : : preferred_color_scheme_to_string ( preference_value ) ) ;
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . set_preferred_color_scheme ( preference_value ) ;
2021-10-23 13:35:14 -03:00
} ,
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 17:55:26 -03:00
settings_menu . add_separator ( ) ;
2022-08-14 14:16:35 -03:00
auto open_settings_action = GUI : : Action : : create ( " Browser &Settings " , Gfx : : Bitmap : : try_load_from_file ( " /res/icons/16x16/settings.png " sv ) . release_value_but_fixme_should_propagate_errors ( ) ,
2022-05-11 15:41:33 -03:00
[ this ] ( auto & ) {
2022-07-11 14:32:29 -03:00
GUI : : Process : : spawn_or_show_error ( this , " /bin/BrowserSettings " sv ) ;
2022-01-31 17:55:26 -03:00
} ) ;
settings_menu . add_action ( move ( open_settings_action ) ) ;
2021-07-21 16:21:03 -03:00
auto & debug_menu = add_menu ( " &Debug " ) ;
2021-05-18 12:32:28 -03:00
debug_menu . add_action ( GUI : : Action : : create (
2022-02-09 15:57:50 -03:00
" Dump &DOM Tree " , g_icon_bag . dom_tree , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " dump-dom-tree " ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-06 23:33:20 -03:00
" Dump &Layout Tree " , g_icon_bag . layout , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " dump-layout-tree " ) ;
2022-02-05 15:01:12 -03:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-08 21:21:10 -03:00
" Dump S&tacking Context Tree " , g_icon_bag . layers , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " dump-stacking-context-tree " ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ) ;
debug_menu . add_action ( GUI : : Action : : create (
2022-02-09 15:57:50 -03:00
" Dump &Style Sheets " , g_icon_bag . filetype_css , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " dump-style-sheets " ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ) ;
2022-02-06 23:33:20 -03:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump &History " , { Mod_Ctrl , Key_H } , g_icon_bag . history , [ this ] ( auto & ) {
2021-05-18 12:32:28 -03:00
active_tab ( ) . m_history . dump ( ) ;
} ) ) ;
2022-01-11 00:06:11 -03:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump C&ookies " , g_icon_bag . cookie , [ this ] ( auto & ) {
2021-05-18 12:32:28 -03:00
auto & tab = active_tab ( ) ;
if ( tab . on_dump_cookies )
tab . on_dump_cookies ( ) ;
} ) ) ;
2022-02-09 15:57:50 -03:00
debug_menu . add_action ( GUI : : Action : : create ( " Dump Loc&al Storage " , g_icon_bag . local_storage , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " dump-local-storage " ) ;
2022-02-08 15:50:14 -03:00
} ) ) ;
2021-05-18 12:32:28 -03:00
debug_menu . add_separator ( ) ;
auto line_box_borders_action = GUI : : Action : : create_checkable (
2021-05-21 13:51:06 -03:00
" Line &Box Borders " , [ this ] ( auto & action ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " set-line-box-borders " , action . is_checked ( ) ? " on " : " off " ) ;
2021-05-18 12:32:28 -03:00
} ,
this ) ;
line_box_borders_action - > set_checked ( false ) ;
debug_menu . add_action ( line_box_borders_action ) ;
debug_menu . add_separator ( ) ;
2022-02-06 23:33:20 -03:00
debug_menu . add_action ( GUI : : Action : : create ( " Collect &Garbage " , { Mod_Ctrl | Mod_Shift , Key_G } , g_icon_bag . trash_can , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " collect-garbage " ) ;
2021-05-18 12:32:28 -03:00
} ) ) ;
2022-02-06 23:33:20 -03:00
debug_menu . add_action ( GUI : : Action : : create ( " Clear &Cache " , { Mod_Ctrl | Mod_Shift , Key_C } , g_icon_bag . clear_cache , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " clear-cache " ) ;
2021-05-18 12:32:28 -03:00
} ) ) ;
m_user_agent_spoof_actions . set_exclusive ( true ) ;
2021-05-21 13:51:06 -03:00
auto & spoof_user_agent_menu = debug_menu . add_submenu ( " Spoof &User Agent " ) ;
2021-05-18 12:32:28 -03:00
m_disable_user_agent_spoofing = GUI : : Action : : create_checkable ( " Disabled " , [ this ] ( auto & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " spoof-user-agent " , Web : : default_user_agent ) ;
2021-05-18 12:32:28 -03: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 23:33:20 -03:00
spoof_user_agent_menu . set_icon ( g_icon_bag . spoof ) ;
2021-05-18 12:32:28 -03: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 & ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " spoof-user-agent " , user_agent ) ;
2021-05-18 12:32:28 -03: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 09:57:20 -03:00
auto custom_user_agent = GUI : : Action : : create_checkable ( " Custom... " , [ this ] ( auto & action ) {
2021-05-18 12:32:28 -03:00
String user_agent ;
2022-07-11 14:32:29 -03:00
if ( GUI : : InputBox : : show ( this , user_agent , " Enter User Agent: " sv , " Custom User Agent " sv ) ! = GUI : : InputBox : : ExecResult : : OK | | user_agent . is_empty ( ) | | user_agent . is_null ( ) ) {
2021-05-18 12:32:28 -03:00
m_disable_user_agent_spoofing - > activate ( ) ;
return ;
}
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " spoof-user-agent " , user_agent ) ;
2021-05-18 12:32:28 -03: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-11 21:10:43 -03:00
debug_menu . add_separator ( ) ;
2022-03-30 19:29:15 -03:00
auto scripting_enabled_action = GUI : : Action : : create_checkable (
" Enable Scripting " , [ this ] ( auto & action ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " scripting " , action . is_checked ( ) ? " on " : " off " ) ;
2022-03-30 19:29:15 -03:00
} ,
this ) ;
scripting_enabled_action - > set_checked ( true ) ;
debug_menu . add_action ( scripting_enabled_action ) ;
2021-09-11 21:10:43 -03:00
auto same_origin_policy_action = GUI : : Action : : create_checkable (
2022-02-08 21:21:10 -03:00
" Enable Same Origin &Policy " , [ this ] ( auto & action ) {
2022-04-06 10:15:07 -03:00
active_tab ( ) . view ( ) . debug_request ( " same-origin-policy " , action . is_checked ( ) ? " on " : " off " ) ;
2021-09-11 21:10:43 -03:00
} ,
this ) ;
2021-10-03 18:39:07 -03:00
same_origin_policy_action - > set_checked ( false ) ;
2021-09-11 21:10:43 -03:00
debug_menu . add_action ( same_origin_policy_action ) ;
2021-07-21 16:21:03 -03:00
auto & help_menu = add_menu ( " &Help " ) ;
2021-05-18 12:32:28 -03:00
help_menu . add_action ( WindowActions : : the ( ) . about_action ( ) ) ;
}
2022-01-20 08:17:17 -03: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 = { } ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " Browser " sv , " Preferences " sv , " SearchEngine " sv , g_search_engine ) ;
2022-01-20 08:17:17 -03:00
} ,
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 14:47:39 -03:00
auto buffer = TRY ( ByteBuffer : : create_uninitialized ( file_size ) ) ;
2022-01-20 08:17:17 -03: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 ( ) ;
2022-07-11 14:32:29 -03:00
auto name = search_engine . get ( " title " sv ) . to_string ( ) ;
auto url_format = search_engine . get ( " url_format " sv ) . to_string ( ) ;
2022-01-20 08:17:17 -03:00
auto action = GUI : : Action : : create_checkable (
name , [ & , url_format ] ( auto & ) {
g_search_engine = url_format ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " Browser " sv , " Preferences " sv , " SearchEngine " sv , g_search_engine ) ;
2022-01-20 08:17:17 -03:00
} ,
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 ;
2022-07-11 14:32:29 -03:00
if ( GUI : : InputBox : : show ( this , search_engine , " Enter URL template: " sv , " Custom Search Engine " sv , " https://host/search?q={} " sv ) ! = GUI : : InputBox : : ExecResult : : OK | | search_engine . is_empty ( ) ) {
2022-01-20 08:17:17 -03:00
m_disable_search_engine_action - > activate ( ) ;
return ;
}
auto argument_count = search_engine . count ( " {} " sv ) ;
if ( argument_count ! = 1 ) {
2022-07-11 14:32:29 -03:00
GUI : : MessageBox : : show ( this , " Invalid format, must contain '{}' once! " sv , " Error " sv , GUI : : MessageBox : : Type : : Error ) ;
2022-01-20 08:17:17 -03:00
m_disable_search_engine_action - > activate ( ) ;
return ;
}
g_search_engine = search_engine ;
2022-07-11 14:32:29 -03:00
Config : : write_string ( " Browser " sv , " Preferences " sv , " SearchEngine " sv , g_search_engine ) ;
2022-01-20 08:17:17 -03:00
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 18:15:20 -03:00
GUI : : TabWidget & BrowserWindow : : tab_widget ( )
{
return * m_tab_widget ;
}
2021-05-18 12:32:28 -03:00
Tab & BrowserWindow : : active_tab ( )
{
2021-06-24 14:53:42 -03:00
return verify_cast < Tab > ( * tab_widget ( ) . active_widget ( ) ) ;
2021-05-18 12:32:28 -03:00
}
2021-05-17 18:15:20 -03: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 11:35:46 -03:00
auto & new_tab = m_tab_widget - > add_tab < Browser : : Tab > ( " New tab " , * this ) ;
2021-05-17 18:15:20 -03:00
m_tab_widget - > set_bar_visible ( ! is_fullscreen ( ) & & m_tab_widget - > children ( ) . size ( ) > 1 ) ;
2021-05-28 21:14:04 -03:00
new_tab . on_title_change = [ this , & new_tab ] ( auto & title ) {
2021-05-17 18:15:20 -03: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 15:12:48 -03:00
m_tab_widget - > deferred_invoke ( [ this , & tab ] {
2021-05-17 18:15:20 -03: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-06 13:21:14 -03:00
new_tab . on_tab_close_other_request = [ this ] ( auto & tab ) {
2021-08-30 15:12:48 -03:00
m_tab_widget - > deferred_invoke ( [ this , & tab ] {
2021-08-06 13:21:14 -03: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 18:15:20 -03: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 ( ) ;
} ;
2022-05-04 16:51:15 -03:00
new_tab . on_get_cookies_entries = [ this ] ( ) {
2022-03-01 13:11:03 -03:00
return m_cookie_jar . get_all_cookies ( ) ;
} ;
2022-04-01 18:14:04 -03:00
new_tab . on_get_local_storage_entries = [ this ] ( ) {
2022-04-06 10:15:07 -03:00
return active_tab ( ) . view ( ) . get_local_storage_entries ( ) ;
2022-04-01 18:14:04 -03:00
} ;
2022-05-07 17:45:43 -03:00
new_tab . on_get_session_storage_entries = [ this ] ( ) {
return active_tab ( ) . view ( ) . get_session_storage_entries ( ) ;
} ;
2021-05-17 18:15:20 -03:00
new_tab . load ( url ) ;
2021-08-07 05:37:26 -03:00
dbgln_if ( SPAM_DEBUG , " Added new tab {:p}, loading {} " , & new_tab , url ) ;
2021-05-17 18:15:20 -03:00
if ( activate )
m_tab_widget - > set_active_widget ( & new_tab ) ;
}
2022-02-01 07:17:37 -03: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-04-07 18:16:47 -03:00
void BrowserWindow : : proxy_mappings_changed ( )
{
tab_widget ( ) . for_each_child_of_type < Browser : : Tab > ( [ ] ( auto & tab ) {
tab . proxy_mappings_changed ( ) ;
return IterationDecision : : Continue ;
} ) ;
}
2022-01-31 17:40:48 -03:00
void BrowserWindow : : config_string_did_change ( String const & domain , String const & group , String const & key , String const & value )
{
2022-04-07 18:16:47 -03:00
if ( domain ! = " Browser " )
2022-01-31 17:40:48 -03:00
return ;
2022-04-07 18:16:47 -03:00
if ( group = = " Preferences " ) {
if ( key = = " SearchEngine " )
Browser : : g_search_engine = value ;
else if ( key = = " Home " )
Browser : : g_home_url = value ;
2022-06-25 16:08:17 -03:00
else if ( key = = " NewTab " )
Browser : : g_new_tab_url = value ;
2022-07-11 14:32:29 -03:00
} else if ( group . starts_with ( " Proxy: " sv ) ) {
2022-04-07 18:16:47 -03:00
dbgln ( " Proxy mapping changed: {}/{} = {} " , group , key , value ) ;
auto proxy_spec = group . substring_view ( 6 ) ;
auto existing_proxy = Browser : : g_proxies . find ( proxy_spec ) ;
if ( existing_proxy . is_end ( ) )
Browser : : g_proxies . append ( proxy_spec ) ;
Browser : : g_proxy_mappings . set ( key , existing_proxy . index ( ) ) ;
proxy_mappings_changed ( ) ;
}
2022-01-31 17:40:48 -03:00
2022-01-31 17:55:26 -03:00
// TODO: ColorScheme
2022-01-31 17:40:48 -03:00
}
void BrowserWindow : : config_bool_did_change ( String const & domain , String const & group , String const & key , bool value )
{
2022-02-01 07:17:37 -03:00
dbgln ( " {} {} {} {} " , domain , group , key , value ) ;
2022-01-31 17:40:48 -03: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 07:17:37 -03:00
} else if ( key = = " EnableContentFilters " ) {
Browser : : g_content_filters_enabled = value ;
content_filters_changed ( ) ;
2022-01-31 17:40:48 -03:00
}
// NOTE: CloseDownloadWidgetOnFinish is read each time in DownloadWindow
}
2021-05-17 18:15:20 -03:00
}