Szontágh Ferenc
2025-03-12 77bc7063534ab317a2ef96249a4f78198d01ef01
initial
1 files modified
12 files added
1318 ■■■■■ changed files
.gitignore 6 ●●●●● patch | view | raw | blame | history
CMakeLists.txt 17 ●●●●● patch | view | raw | blame | history
assets/gui.fbp 646 ●●●●● patch | view | raw | blame | history
src/BrowserApp.cpp 7 ●●●●● patch | view | raw | blame | history
src/BrowserApp.h 12 ●●●●● patch | view | raw | blame | history
src/BrowserFrame.cpp 150 ●●●●● patch | view | raw | blame | history
src/BrowserFrame.h 54 ●●●●● patch | view | raw | blame | history
src/base/wxBrowserBase.cpp 88 ●●●●● patch | view | raw | blame | history
src/base/wxBrowserBase.h 73 ●●●●● patch | view | raw | blame | history
src/handlers/CurlHttpHandler.h 67 ●●●●● patch | view | raw | blame | history
src/handlers/CurlHttpsHandler.h 87 ●●●●● patch | view | raw | blame | history
src/handlers/WebViewHandler.h 107 ●●●●● patch | view | raw | blame | history
src/main.cpp 4 ●●●● patch | view | raw | blame | history
.gitignore
@@ -19,3 +19,9 @@
*.exe
*.out
*.app
.cache
.DS_Store
.vscode
.idea
build
CMakeLists.txt
New file
@@ -0,0 +1,17 @@
cmake_minimum_required(VERSION 3.10)
project(wxWidgetsBrowser)
find_package(CURL REQUIRED)
find_package(wxWidgets REQUIRED COMPONENTS core base webview aui)
include(${wxWidgets_USE_FILE})
add_executable(wxWidgetsBrowser
    src/main.cpp
    src/BrowserApp.cpp
    src/BrowserFrame.cpp
    src/base/wxBrowserBase.cpp
)
target_link_libraries(wxWidgetsBrowser ${wxWidgets_LIBRARIES} ${CURL_LIBRARIES})
assets/gui.fbp
New file
@@ -0,0 +1,646 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<wxFormBuilder_Project>
  <FileVersion major="1" minor="18"/>
  <object class="Project" expanded="true">
    <property name="code_generation">C++</property>
    <property name="cpp_class_decoration">; </property>
    <property name="cpp_disconnect_events">0</property>
    <property name="cpp_event_generation">connect</property>
    <property name="cpp_help_provider">none</property>
    <property name="cpp_namespace"></property>
    <property name="cpp_precompiled_header"></property>
    <property name="cpp_use_array_enum">0</property>
    <property name="cpp_use_enum">1</property>
    <property name="embedded_files_path">res</property>
    <property name="encoding">UTF-8</property>
    <property name="file">wxBrowserBase</property>
    <property name="first_id">6000</property>
    <property name="internationalize">1</property>
    <property name="lua_skip_events">1</property>
    <property name="lua_ui_table">UI</property>
    <property name="name">wxBrowser</property>
    <property name="path">../src/base</property>
    <property name="php_disconnect_events">0</property>
    <property name="php_disconnect_mode">source_name</property>
    <property name="php_skip_events">1</property>
    <property name="python_disconnect_events">0</property>
    <property name="python_disconnect_mode">source_name</property>
    <property name="python_image_path_wrapper_function_name"></property>
    <property name="python_indent_with_spaces">1</property>
    <property name="python_skip_events">1</property>
    <property name="relative_path">1</property>
    <property name="use_microsoft_bom">0</property>
    <property name="use_native_eol">0</property>
    <object class="Frame" expanded="true">
      <property name="aui_managed">0</property>
      <property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
      <property name="bg"></property>
      <property name="center">wxBOTH</property>
      <property name="context_help"></property>
      <property name="context_menu">1</property>
      <property name="drag_accept_files">0</property>
      <property name="enabled">1</property>
      <property name="event_handler">impl_virtual</property>
      <property name="extra_style"></property>
      <property name="fg"></property>
      <property name="font"></property>
      <property name="hidden">0</property>
      <property name="id">wxID_ANY</property>
      <property name="maximum_size"></property>
      <property name="minimum_size">-1,-1</property>
      <property name="name">wxBrowserBase</property>
      <property name="pos"></property>
      <property name="size">800,600</property>
      <property name="style">wxDEFAULT_FRAME_STYLE</property>
      <property name="subclass">; ; forward_declare</property>
      <property name="title">wxBrowser</property>
      <property name="tooltip"></property>
      <property name="two_step_creation">0</property>
      <property name="window_extra_style"></property>
      <property name="window_name"></property>
      <property name="window_style">wxTAB_TRAVERSAL</property>
      <property name="xrc_skip_sizer">1</property>
      <object class="wxBoxSizer" expanded="true">
        <property name="minimum_size"></property>
        <property name="name">bSizer1</property>
        <property name="orient">wxVERTICAL</property>
        <property name="permission">none</property>
        <object class="sizeritem" expanded="true">
          <property name="border">5</property>
          <property name="flag">wxEXPAND</property>
          <property name="proportion">0</property>
          <object class="wxBoxSizer" expanded="false">
            <property name="minimum_size"></property>
            <property name="name">bSizer2</property>
            <property name="orient">wxHORIZONTAL</property>
            <property name="permission">none</property>
            <object class="sizeritem" expanded="false">
              <property name="border">5</property>
              <property name="flag">wxALL</property>
              <property name="proportion">0</property>
              <object class="wxButton" expanded="false">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
                <property name="TopDockable">1</property>
                <property name="aui_layer">0</property>
                <property name="aui_name"></property>
                <property name="aui_position">0</property>
                <property name="aui_row">0</property>
                <property name="auth_needed">0</property>
                <property name="best_size"></property>
                <property name="bg"></property>
                <property name="bitmap">Load From Art Provider; wxART_GO_BACK; wxART_MENU</property>
                <property name="caption"></property>
                <property name="caption_visible">1</property>
                <property name="center_pane">0</property>
                <property name="close_button">1</property>
                <property name="context_help"></property>
                <property name="context_menu">1</property>
                <property name="current"></property>
                <property name="default">0</property>
                <property name="default_pane">0</property>
                <property name="disabled"></property>
                <property name="dock">Dock</property>
                <property name="dock_fixed">0</property>
                <property name="docking">Left</property>
                <property name="drag_accept_files">0</property>
                <property name="enabled">1</property>
                <property name="fg"></property>
                <property name="floatable">1</property>
                <property name="focus"></property>
                <property name="font"></property>
                <property name="gripper">0</property>
                <property name="hidden">0</property>
                <property name="id">wxID_ANY</property>
                <property name="label">Back</property>
                <property name="margins"></property>
                <property name="markup">0</property>
                <property name="max_size"></property>
                <property name="maximize_button">0</property>
                <property name="maximum_size"></property>
                <property name="min_size"></property>
                <property name="minimize_button">0</property>
                <property name="minimum_size"></property>
                <property name="moveable">1</property>
                <property name="name">m_back</property>
                <property name="pane_border">1</property>
                <property name="pane_position"></property>
                <property name="pane_size"></property>
                <property name="permission">protected</property>
                <property name="pin_button">1</property>
                <property name="pos"></property>
                <property name="position"></property>
                <property name="pressed"></property>
                <property name="resize">Resizable</property>
                <property name="show">1</property>
                <property name="size"></property>
                <property name="style"></property>
                <property name="subclass">; ; forward_declare</property>
                <property name="toolbar_pane">0</property>
                <property name="tooltip"></property>
                <property name="validator_data_type"></property>
                <property name="validator_style">wxFILTER_NONE</property>
                <property name="validator_type">wxDefaultValidator</property>
                <property name="validator_variable"></property>
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style"></property>
                <event name="OnButtonClick">OnBack</event>
              </object>
            </object>
            <object class="sizeritem" expanded="false">
              <property name="border">5</property>
              <property name="flag">wxALL</property>
              <property name="proportion">0</property>
              <object class="wxButton" expanded="false">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
                <property name="TopDockable">1</property>
                <property name="aui_layer">0</property>
                <property name="aui_name"></property>
                <property name="aui_position">0</property>
                <property name="aui_row">0</property>
                <property name="auth_needed">0</property>
                <property name="best_size"></property>
                <property name="bg"></property>
                <property name="bitmap">Load From Art Provider; wxART_GO_FORWARD; wxART_MENU</property>
                <property name="caption"></property>
                <property name="caption_visible">1</property>
                <property name="center_pane">0</property>
                <property name="close_button">1</property>
                <property name="context_help"></property>
                <property name="context_menu">1</property>
                <property name="current"></property>
                <property name="default">0</property>
                <property name="default_pane">0</property>
                <property name="disabled"></property>
                <property name="dock">Dock</property>
                <property name="dock_fixed">0</property>
                <property name="docking">Left</property>
                <property name="drag_accept_files">0</property>
                <property name="enabled">1</property>
                <property name="fg"></property>
                <property name="floatable">1</property>
                <property name="focus"></property>
                <property name="font"></property>
                <property name="gripper">0</property>
                <property name="hidden">0</property>
                <property name="id">wxID_ANY</property>
                <property name="label">Forward</property>
                <property name="margins"></property>
                <property name="markup">0</property>
                <property name="max_size"></property>
                <property name="maximize_button">0</property>
                <property name="maximum_size"></property>
                <property name="min_size"></property>
                <property name="minimize_button">0</property>
                <property name="minimum_size"></property>
                <property name="moveable">1</property>
                <property name="name">m_forward</property>
                <property name="pane_border">1</property>
                <property name="pane_position"></property>
                <property name="pane_size"></property>
                <property name="permission">protected</property>
                <property name="pin_button">1</property>
                <property name="pos"></property>
                <property name="position"></property>
                <property name="pressed"></property>
                <property name="resize">Resizable</property>
                <property name="show">1</property>
                <property name="size"></property>
                <property name="style"></property>
                <property name="subclass">; ; forward_declare</property>
                <property name="toolbar_pane">0</property>
                <property name="tooltip"></property>
                <property name="validator_data_type"></property>
                <property name="validator_style">wxFILTER_NONE</property>
                <property name="validator_type">wxDefaultValidator</property>
                <property name="validator_variable"></property>
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style"></property>
                <event name="OnButtonClick">OnForward</event>
              </object>
            </object>
            <object class="sizeritem" expanded="false">
              <property name="border">5</property>
              <property name="flag">wxALL</property>
              <property name="proportion">0</property>
              <object class="wxButton" expanded="false">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
                <property name="TopDockable">1</property>
                <property name="aui_layer">0</property>
                <property name="aui_name"></property>
                <property name="aui_position">0</property>
                <property name="aui_row">0</property>
                <property name="auth_needed">0</property>
                <property name="best_size"></property>
                <property name="bg"></property>
                <property name="bitmap">Load From Art Provider; wxART_GO_HOME; wxART_MENU</property>
                <property name="caption"></property>
                <property name="caption_visible">1</property>
                <property name="center_pane">0</property>
                <property name="close_button">1</property>
                <property name="context_help"></property>
                <property name="context_menu">1</property>
                <property name="current"></property>
                <property name="default">0</property>
                <property name="default_pane">0</property>
                <property name="disabled"></property>
                <property name="dock">Dock</property>
                <property name="dock_fixed">0</property>
                <property name="docking">Left</property>
                <property name="drag_accept_files">0</property>
                <property name="enabled">1</property>
                <property name="fg"></property>
                <property name="floatable">1</property>
                <property name="focus"></property>
                <property name="font"></property>
                <property name="gripper">0</property>
                <property name="hidden">0</property>
                <property name="id">wxID_ANY</property>
                <property name="label">Home</property>
                <property name="margins"></property>
                <property name="markup">0</property>
                <property name="max_size"></property>
                <property name="maximize_button">0</property>
                <property name="maximum_size"></property>
                <property name="min_size"></property>
                <property name="minimize_button">0</property>
                <property name="minimum_size"></property>
                <property name="moveable">1</property>
                <property name="name">m_home</property>
                <property name="pane_border">1</property>
                <property name="pane_position"></property>
                <property name="pane_size"></property>
                <property name="permission">protected</property>
                <property name="pin_button">1</property>
                <property name="pos"></property>
                <property name="position"></property>
                <property name="pressed"></property>
                <property name="resize">Resizable</property>
                <property name="show">1</property>
                <property name="size"></property>
                <property name="style"></property>
                <property name="subclass">; ; forward_declare</property>
                <property name="toolbar_pane">0</property>
                <property name="tooltip"></property>
                <property name="validator_data_type"></property>
                <property name="validator_style">wxFILTER_NONE</property>
                <property name="validator_type">wxDefaultValidator</property>
                <property name="validator_variable"></property>
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style"></property>
                <event name="OnButtonClick">OnHome</event>
              </object>
            </object>
            <object class="sizeritem" expanded="false">
              <property name="border">5</property>
              <property name="flag">wxALL</property>
              <property name="proportion">0</property>
              <object class="wxButton" expanded="false">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
                <property name="TopDockable">1</property>
                <property name="aui_layer">0</property>
                <property name="aui_name"></property>
                <property name="aui_position">0</property>
                <property name="aui_row">0</property>
                <property name="auth_needed">0</property>
                <property name="best_size"></property>
                <property name="bg"></property>
                <property name="bitmap"></property>
                <property name="caption"></property>
                <property name="caption_visible">1</property>
                <property name="center_pane">0</property>
                <property name="close_button">1</property>
                <property name="context_help"></property>
                <property name="context_menu">1</property>
                <property name="current"></property>
                <property name="default">0</property>
                <property name="default_pane">0</property>
                <property name="disabled"></property>
                <property name="dock">Dock</property>
                <property name="dock_fixed">0</property>
                <property name="docking">Left</property>
                <property name="drag_accept_files">0</property>
                <property name="enabled">1</property>
                <property name="fg"></property>
                <property name="floatable">1</property>
                <property name="focus"></property>
                <property name="font"></property>
                <property name="gripper">0</property>
                <property name="hidden">0</property>
                <property name="id">wxID_ANY</property>
                <property name="label">Refresh</property>
                <property name="margins"></property>
                <property name="markup">0</property>
                <property name="max_size"></property>
                <property name="maximize_button">0</property>
                <property name="maximum_size"></property>
                <property name="min_size"></property>
                <property name="minimize_button">0</property>
                <property name="minimum_size"></property>
                <property name="moveable">1</property>
                <property name="name">m_refresh</property>
                <property name="pane_border">1</property>
                <property name="pane_position"></property>
                <property name="pane_size"></property>
                <property name="permission">protected</property>
                <property name="pin_button">1</property>
                <property name="pos"></property>
                <property name="position"></property>
                <property name="pressed"></property>
                <property name="resize">Resizable</property>
                <property name="show">1</property>
                <property name="size"></property>
                <property name="style"></property>
                <property name="subclass">; ; forward_declare</property>
                <property name="toolbar_pane">0</property>
                <property name="tooltip"></property>
                <property name="validator_data_type"></property>
                <property name="validator_style">wxFILTER_NONE</property>
                <property name="validator_type">wxDefaultValidator</property>
                <property name="validator_variable"></property>
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style"></property>
                <event name="OnButtonClick">OnReload</event>
              </object>
            </object>
            <object class="sizeritem" expanded="false">
              <property name="border">5</property>
              <property name="flag">wxALL</property>
              <property name="proportion">1</property>
              <object class="wxTextCtrl" expanded="false">
                <property name="BottomDockable">1</property>
                <property name="LeftDockable">1</property>
                <property name="RightDockable">1</property>
                <property name="TopDockable">1</property>
                <property name="aui_layer">0</property>
                <property name="aui_name"></property>
                <property name="aui_position">0</property>
                <property name="aui_row">0</property>
                <property name="best_size"></property>
                <property name="bg"></property>
                <property name="caption"></property>
                <property name="caption_visible">1</property>
                <property name="center_pane">0</property>
                <property name="close_button">1</property>
                <property name="context_help"></property>
                <property name="context_menu">1</property>
                <property name="default_pane">0</property>
                <property name="dock">Dock</property>
                <property name="dock_fixed">0</property>
                <property name="docking">Left</property>
                <property name="drag_accept_files">0</property>
                <property name="enabled">1</property>
                <property name="fg"></property>
                <property name="floatable">1</property>
                <property name="font"></property>
                <property name="gripper">0</property>
                <property name="hidden">0</property>
                <property name="id">wxID_ANY</property>
                <property name="max_size"></property>
                <property name="maximize_button">0</property>
                <property name="maximum_size"></property>
                <property name="maxlength">0</property>
                <property name="min_size"></property>
                <property name="minimize_button">0</property>
                <property name="minimum_size"></property>
                <property name="moveable">1</property>
                <property name="name">m_urlbar</property>
                <property name="pane_border">1</property>
                <property name="pane_position"></property>
                <property name="pane_size"></property>
                <property name="permission">protected</property>
                <property name="pin_button">1</property>
                <property name="pos"></property>
                <property name="resize">Resizable</property>
                <property name="show">1</property>
                <property name="size"></property>
                <property name="style">wxTE_PROCESS_ENTER</property>
                <property name="subclass">; ; forward_declare</property>
                <property name="toolbar_pane">0</property>
                <property name="tooltip"></property>
                <property name="validator_data_type"></property>
                <property name="validator_style">wxFILTER_NONE</property>
                <property name="validator_type">wxDefaultValidator</property>
                <property name="validator_variable"></property>
                <property name="value"></property>
                <property name="window_extra_style"></property>
                <property name="window_name"></property>
                <property name="window_style"></property>
                <event name="OnLeftUp">m_urlbarOnLeftUp</event>
                <event name="OnSetFocus">m_urlbarOnSetFocus</event>
                <event name="OnTextEnter">OnUrlEnter</event>
              </object>
            </object>
          </object>
        </object>
        <object class="sizeritem" expanded="false">
          <property name="border">5</property>
          <property name="flag">wxALL|wxEXPAND</property>
          <property name="proportion">0</property>
          <object class="wxGauge" expanded="false">
            <property name="BottomDockable">1</property>
            <property name="LeftDockable">1</property>
            <property name="RightDockable">1</property>
            <property name="TopDockable">1</property>
            <property name="aui_layer">0</property>
            <property name="aui_name"></property>
            <property name="aui_position">0</property>
            <property name="aui_row">0</property>
            <property name="best_size"></property>
            <property name="bg"></property>
            <property name="caption"></property>
            <property name="caption_visible">1</property>
            <property name="center_pane">0</property>
            <property name="close_button">1</property>
            <property name="context_help"></property>
            <property name="context_menu">1</property>
            <property name="default_pane">0</property>
            <property name="dock">Dock</property>
            <property name="dock_fixed">0</property>
            <property name="docking">Left</property>
            <property name="drag_accept_files">0</property>
            <property name="enabled">1</property>
            <property name="fg"></property>
            <property name="floatable">1</property>
            <property name="font"></property>
            <property name="gripper">0</property>
            <property name="hidden">0</property>
            <property name="id">wxID_ANY</property>
            <property name="max_size"></property>
            <property name="maximize_button">0</property>
            <property name="maximum_size"></property>
            <property name="min_size"></property>
            <property name="minimize_button">0</property>
            <property name="minimum_size"></property>
            <property name="moveable">1</property>
            <property name="name">m_gauge1</property>
            <property name="pane_border">1</property>
            <property name="pane_position"></property>
            <property name="pane_size"></property>
            <property name="permission">protected</property>
            <property name="pin_button">1</property>
            <property name="pos"></property>
            <property name="range">100</property>
            <property name="resize">Resizable</property>
            <property name="show">1</property>
            <property name="size"></property>
            <property name="style">wxGA_HORIZONTAL</property>
            <property name="subclass">; ; forward_declare</property>
            <property name="toolbar_pane">0</property>
            <property name="tooltip"></property>
            <property name="validator_data_type"></property>
            <property name="validator_style">wxFILTER_NONE</property>
            <property name="validator_type">wxDefaultValidator</property>
            <property name="validator_variable"></property>
            <property name="value">0</property>
            <property name="window_extra_style"></property>
            <property name="window_name"></property>
            <property name="window_style"></property>
          </object>
        </object>
        <object class="sizeritem" expanded="false">
          <property name="border">5</property>
          <property name="flag">wxEXPAND | wxALL</property>
          <property name="proportion">1</property>
          <object class="wxAuiNotebook" expanded="false">
            <property name="BottomDockable">1</property>
            <property name="LeftDockable">1</property>
            <property name="RightDockable">1</property>
            <property name="TopDockable">1</property>
            <property name="aui_layer">0</property>
            <property name="aui_name"></property>
            <property name="aui_position">0</property>
            <property name="aui_row">0</property>
            <property name="best_size"></property>
            <property name="bg"></property>
            <property name="caption"></property>
            <property name="caption_visible">1</property>
            <property name="center_pane">0</property>
            <property name="close_button">1</property>
            <property name="context_help"></property>
            <property name="context_menu">1</property>
            <property name="default_pane">0</property>
            <property name="dock">Dock</property>
            <property name="dock_fixed">0</property>
            <property name="docking">Left</property>
            <property name="drag_accept_files">0</property>
            <property name="enabled">1</property>
            <property name="fg"></property>
            <property name="floatable">1</property>
            <property name="font"></property>
            <property name="gripper">0</property>
            <property name="hidden">0</property>
            <property name="id">wxID_ANY</property>
            <property name="max_size"></property>
            <property name="maximize_button">0</property>
            <property name="maximum_size"></property>
            <property name="min_size"></property>
            <property name="minimize_button">0</property>
            <property name="minimum_size"></property>
            <property name="moveable">1</property>
            <property name="name">m_auinotebook1</property>
            <property name="pane_border">1</property>
            <property name="pane_position"></property>
            <property name="pane_size"></property>
            <property name="permission">protected</property>
            <property name="pin_button">1</property>
            <property name="pos"></property>
            <property name="resize">Resizable</property>
            <property name="show">1</property>
            <property name="size"></property>
            <property name="style">wxAUI_NB_DEFAULT_STYLE</property>
            <property name="subclass">; ; forward_declare</property>
            <property name="tab_ctrl_height">64</property>
            <property name="toolbar_pane">0</property>
            <property name="tooltip"></property>
            <property name="uniform_bitmap_size"></property>
            <property name="window_extra_style"></property>
            <property name="window_name"></property>
            <property name="window_style"></property>
            <event name="OnAuiNotebookPageChanged">OnPageChanged</event>
            <event name="OnAuiNotebookPageChanging">OnPageChanging</event>
            <event name="OnAuiNotebookPageClose">OnPageClose</event>
            <event name="OnAuiNotebookPageClosed">OnPageClosed</event>
          </object>
        </object>
      </object>
      <object class="wxStatusBar" expanded="true">
        <property name="bg"></property>
        <property name="context_help"></property>
        <property name="context_menu">1</property>
        <property name="drag_accept_files">0</property>
        <property name="enabled">1</property>
        <property name="fg"></property>
        <property name="fields">1</property>
        <property name="font"></property>
        <property name="hidden">0</property>
        <property name="id">wxID_ANY</property>
        <property name="maximum_size"></property>
        <property name="minimum_size"></property>
        <property name="name">m_statusBar1</property>
        <property name="permission">protected</property>
        <property name="pos"></property>
        <property name="size"></property>
        <property name="style">wxSTB_SIZEGRIP</property>
        <property name="subclass">; ; forward_declare</property>
        <property name="tooltip"></property>
        <property name="window_extra_style"></property>
        <property name="window_name"></property>
        <property name="window_style"></property>
      </object>
      <object class="wxMenuBar" expanded="true">
        <property name="bg"></property>
        <property name="context_help"></property>
        <property name="context_menu">1</property>
        <property name="drag_accept_files">0</property>
        <property name="enabled">1</property>
        <property name="fg"></property>
        <property name="font"></property>
        <property name="hidden">0</property>
        <property name="id">wxID_ANY</property>
        <property name="maximum_size"></property>
        <property name="minimum_size"></property>
        <property name="name">m_menubar1</property>
        <property name="permission">protected</property>
        <property name="pos"></property>
        <property name="size"></property>
        <property name="style"></property>
        <property name="subclass">; ; forward_declare</property>
        <property name="tooltip"></property>
        <property name="window_extra_style"></property>
        <property name="window_name"></property>
        <property name="window_style"></property>
        <object class="wxMenu" expanded="true">
          <property name="label">&amp;File</property>
          <property name="name">m_menu_file</property>
          <property name="permission">protected</property>
          <object class="wxMenuItem" expanded="true">
            <property name="bitmap"></property>
            <property name="checked">0</property>
            <property name="enabled">1</property>
            <property name="help">Open a new tab</property>
            <property name="id">wxID_ANY</property>
            <property name="kind">wxITEM_NORMAL</property>
            <property name="label">New &amp;tab</property>
            <property name="name">m_menuItem1</property>
            <property name="permission">none</property>
            <property name="shortcut">CTRL+T</property>
            <property name="unchecked_bitmap"></property>
            <event name="OnMenuSelection">OnNewTab</event>
          </object>
        </object>
      </object>
    </object>
  </object>
</wxFormBuilder_Project>
src/BrowserApp.cpp
New file
@@ -0,0 +1,7 @@
#include "BrowserApp.h"
bool BrowserApp::OnInit() {
  BrowserFrame *frame = new BrowserFrame(NULL);
  frame->Show(true);
  return true;
}
src/BrowserApp.h
New file
@@ -0,0 +1,12 @@
#ifndef BROWSERAPP_H
#define BROWSERAPP_H
#include "BrowserFrame.h"
#include <wx/wx.h>
class BrowserApp : public wxApp {
public:
  virtual bool OnInit();
};
#endif // BROWSERAPP_H
src/BrowserFrame.cpp
New file
@@ -0,0 +1,150 @@
#include "BrowserFrame.h"
#include "handlers/CurlHttpHandler.h"
#include "handlers/CurlHttpsHandler.h"
BrowserFrame::BrowserFrame(wxWindow *parent) : wxBrowserBase(parent) {
  wxCommandEvent event;
  event.SetString("https://www.google.com");
  this->OnNewTab(event);
}
BrowserFrame::~BrowserFrame() { webViews.clear(); }
void BrowserFrame::OnPageClose(wxAuiNotebookEvent &event) { event.Skip(); }
void BrowserFrame::OnPageClosed(wxAuiNotebookEvent &event) {
  // get the closed tab index
  int closed = event.GetSelection();
  // remove the tab from the map
  this->webViewtabMap.erase(closed);
  // remove the webview from the map
  this->webViews.erase(this->webViewtabMap[closed]);
  if (this->currentWebView == this->webViewtabMap[closed]) {
    this->currentWebView = nullptr;
  }
  if (this->webViewtabMap.size() == 0) {
    wxCommandEvent event = wxCommandEvent();
    event.SetString("https://www.google.com");
    this->OnNewTab(event);
  }
  event.Skip();
}
void BrowserFrame::OnPageChanging(wxAuiNotebookEvent &event) { event.Skip(); }
void BrowserFrame::OnPageChanged(wxAuiNotebookEvent &event) { event.Skip(); }
void BrowserFrame::OnUrlEnter(wxCommandEvent &event) {
  wxString url = m_urlbar->GetValue();
  if (!url.StartsWith("http://") && !url.StartsWith("https://")) {
    wxRegEx domainRegex("^([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,}$");
    url = domainRegex.Matches(url) ? "https://" + url
                                   : "https://www.google.com/search?q=" + url;
    this->m_urlbar->SetValue(url);
  }
  if (this->currentWebView) {
    url.Prepend("p");
    this->currentWebView->LoadURL(url);
  }
}
void BrowserFrame::OnNewTab(wxCommandEvent &event) {
  wxPanel *panel = new wxPanel(m_auinotebook1);
  wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
  wxString url = "https://www.google.com";
  if (!event.GetString().IsEmpty()) {
    url = event.GetString();
  }
  wxWebView *webView = wxWebView::New(panel, wxID_ANY, url);
  webView->RegisterHandler(
      wxSharedPtr<wxWebViewHandler>(new CurlHttpHandler()));
  webView->RegisterHandler(
      wxSharedPtr<wxWebViewHandler>(new CurlHttpsHandler()));
  sizer->Add(webView, 1, wxEXPAND);
  panel->SetSizer(sizer);
  m_auinotebook1->AddPage(panel, "New Tab", true);
  m_auinotebook1->SetSelection(m_auinotebook1->GetPageCount() - 1);
  this->m_urlbar->SetValue(url);
  this->currentWebView = webView;
  this->webViews[webView] = std::make_shared<WebViewHandler>(
      webView, std::bind(&BrowserFrame::WebViewHandlerCallback, this,
                         std::placeholders::_1, std::placeholders::_2,
                         std::placeholders::_3));
  this->webViewtabMap[m_auinotebook1->GetPageCount() - 1] = webView;
}
void BrowserFrame::OnReload(wxCommandEvent &event) {
  if (this->currentWebView) {
    this->currentWebView->Reload();
  }
}
void BrowserFrame::OnBack(wxCommandEvent &event) {
  if (this->currentWebView) {
    this->currentWebView->GoBack();
  }
}
void BrowserFrame::OnForward(wxCommandEvent &event) {
  if (this->currentWebView) {
    this->currentWebView->GoForward();
  }
}
void BrowserFrame::OnHome(wxCommandEvent &event) {
  if (this->currentWebView) {
    this->currentWebView->LoadURL("https://www.google.com");
  }
}
void BrowserFrame::m_urlbarOnSetFocus(wxFocusEvent &event) {
  this->m_urlbar->SetSelection(0, this->m_urlbar->GetValue().size());
}
void BrowserFrame::m_urlbarOnLeftUp(wxMouseEvent &event) {
  this->m_urlbar->SetSelection(0, this->m_urlbar->GetValue().size());
}
size_t BrowserFrame::GetTabIndex(wxWebView *webView) {
  for (auto &pair : this->webViewtabMap) {
    if (pair.second == webView) {
      return pair.first;
    }
  }
  return wxNOT_FOUND;
}
void BrowserFrame::ChangeTabIndex(wxWebView *webView, int index) {
  auto it = this->webViewtabMap.find(index);
  if (it != this->webViewtabMap.end()) {
    this->webViewtabMap[index] = webView;
    this->webViewtabMap.erase(it);
  }
}
void BrowserFrame::WebViewHandlerCallback(WebViewHandler::CallbackType type,
                                          const wxString data,
                                          WebViewHandler *handler) {
  switch (type) {
  case WebViewHandler::CallbackType::OnTitleChanged: {
    const auto index = this->GetTabIndex(handler->GetwebView());
    if (index == wxNOT_FOUND) {
      return;
    }
    wxString title = data;
    if (data.size() > 50) {
      title = data.substr(0, 50) + "...";
      this->m_auinotebook1->SetPageToolTip(index, data);
    }
    this->m_auinotebook1->SetPageText(index, data);
  } break;
  case WebViewHandler::CallbackType::OnNavigated:
    this->m_urlbar->SetValue(data);
    break;
  case WebViewHandler::CallbackType::OnNewWindow: {
    wxCommandEvent event = wxCommandEvent();
    event.SetString(data);
    this->OnNewTab(event);
  } break;
  default:
    break;
  }
}
src/BrowserFrame.h
New file
@@ -0,0 +1,54 @@
#ifndef __BrowserFrame__
#define __BrowserFrame__
/**
@file
Subclass of BrowserFrame, which is generated by wxFormBuilder.
*/
#include <map>
#include <memory>
#include <wx/panel.h>
#include <wx/regex.h>
#include <wx/webview.h>
#include "base/wxBrowserBase.h"
#include "handlers/WebViewHandler.h"
//// end generated include
/** Implementing BrowserFrame */
class BrowserFrame : public wxBrowserBase {
protected:
  // Handlers for BrowserFrame events.
  void OnPageClose(wxAuiNotebookEvent &event) override;
  void OnPageClosed(wxAuiNotebookEvent &event) override;
  void OnPageChanging(wxAuiNotebookEvent &event) override;
  void OnPageChanged(wxAuiNotebookEvent &event) override;
  void OnUrlEnter(wxCommandEvent &event) override;
  void OnNewTab(wxCommandEvent &event) override;
  void OnReload(wxCommandEvent &event) override;
  void OnBack(wxCommandEvent &event) override;
  void OnForward(wxCommandEvent &event) override;
  void OnHome(wxCommandEvent &event) override;
  void m_urlbarOnSetFocus(wxFocusEvent &event) override;
  void m_urlbarOnLeftUp(wxMouseEvent &event) override;
public:
  /** Constructor */
  BrowserFrame(wxWindow *parent);
  ~BrowserFrame();
private:
  // webview, tab position
  std::map<wxWebView *, std::shared_ptr<WebViewHandler>> webViews;
  std::map<int, wxWebView *> webViewtabMap;
  int currentWebViewIndex = 0;
  wxWebView *currentWebView = nullptr;
  size_t GetTabIndex(wxWebView *webView);
  void ChangeTabIndex(wxWebView *webView, int index);
  void WebViewHandlerCallback(WebViewHandler::CallbackType type,
                              const wxString data, WebViewHandler *handler);
};
#endif // __BrowserFrame__
src/base/wxBrowserBase.cpp
New file
@@ -0,0 +1,88 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "wxBrowserBase.h"
///////////////////////////////////////////////////////////////////////////
wxBrowserBase::wxBrowserBase( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxFrame( parent, id, title, pos, size, style )
{
    this->SetSizeHints( wxSize( -1,-1 ), wxDefaultSize );
    wxBoxSizer* bSizer1;
    bSizer1 = new wxBoxSizer( wxVERTICAL );
    wxBoxSizer* bSizer2;
    bSizer2 = new wxBoxSizer( wxHORIZONTAL );
    m_back = new wxButton( this, wxID_ANY, _("Back"), wxDefaultPosition, wxDefaultSize, 0 );
    m_back->SetBitmap( wxArtProvider::GetBitmap( wxASCII_STR(wxART_GO_BACK), wxASCII_STR(wxART_MENU) ) );
    bSizer2->Add( m_back, 0, wxALL, 5 );
    m_forward = new wxButton( this, wxID_ANY, _("Forward"), wxDefaultPosition, wxDefaultSize, 0 );
    m_forward->SetBitmap( wxArtProvider::GetBitmap( wxASCII_STR(wxART_GO_FORWARD), wxASCII_STR(wxART_MENU) ) );
    bSizer2->Add( m_forward, 0, wxALL, 5 );
    m_home = new wxButton( this, wxID_ANY, _("Home"), wxDefaultPosition, wxDefaultSize, 0 );
    m_home->SetBitmap( wxArtProvider::GetBitmap( wxASCII_STR(wxART_GO_HOME), wxASCII_STR(wxART_MENU) ) );
    bSizer2->Add( m_home, 0, wxALL, 5 );
    m_refresh = new wxButton( this, wxID_ANY, _("Refresh"), wxDefaultPosition, wxDefaultSize, 0 );
    bSizer2->Add( m_refresh, 0, wxALL, 5 );
    m_urlbar = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
    bSizer2->Add( m_urlbar, 1, wxALL, 5 );
    bSizer1->Add( bSizer2, 0, wxEXPAND, 5 );
    m_gauge1 = new wxGauge( this, wxID_ANY, 100, wxDefaultPosition, wxDefaultSize, wxGA_HORIZONTAL );
    m_gauge1->SetValue( 0 );
    bSizer1->Add( m_gauge1, 0, wxALL|wxEXPAND, 5 );
    m_auinotebook1 = new wxAuiNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_DEFAULT_STYLE );
    bSizer1->Add( m_auinotebook1, 1, wxEXPAND | wxALL, 5 );
    this->SetSizer( bSizer1 );
    this->Layout();
    m_statusBar1 = this->CreateStatusBar( 1, wxSTB_SIZEGRIP, wxID_ANY );
    m_menubar1 = new wxMenuBar( 0 );
    m_menu_file = new wxMenu();
    wxMenuItem* m_menuItem1;
    m_menuItem1 = new wxMenuItem( m_menu_file, wxID_ANY, wxString( _("New &tab") ) + wxT('\t') + wxT("CTRL+T"), _("Open a new tab"), wxITEM_NORMAL );
    m_menu_file->Append( m_menuItem1 );
    m_menubar1->Append( m_menu_file, _("&File") );
    this->SetMenuBar( m_menubar1 );
    this->Centre( wxBOTH );
    // Connect Events
    m_back->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxBrowserBase::OnBack ), NULL, this );
    m_forward->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxBrowserBase::OnForward ), NULL, this );
    m_home->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxBrowserBase::OnHome ), NULL, this );
    m_refresh->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( wxBrowserBase::OnReload ), NULL, this );
    m_urlbar->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( wxBrowserBase::m_urlbarOnLeftUp ), NULL, this );
    m_urlbar->Connect( wxEVT_SET_FOCUS, wxFocusEventHandler( wxBrowserBase::m_urlbarOnSetFocus ), NULL, this );
    m_urlbar->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( wxBrowserBase::OnUrlEnter ), NULL, this );
    m_auinotebook1->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( wxBrowserBase::OnPageChanged ), NULL, this );
    m_auinotebook1->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, wxAuiNotebookEventHandler( wxBrowserBase::OnPageChanging ), NULL, this );
    m_auinotebook1->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( wxBrowserBase::OnPageClose ), NULL, this );
    m_auinotebook1->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( wxBrowserBase::OnPageClosed ), NULL, this );
    m_menu_file->Bind(wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( wxBrowserBase::OnNewTab ), this, m_menuItem1->GetId());
}
wxBrowserBase::~wxBrowserBase()
{
}
src/base/wxBrowserBase.h
New file
@@ -0,0 +1,73 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include <wx/button.h>
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/gauge.h>
#include <wx/aui/auibook.h>
#include <wx/statusbr.h>
#include <wx/menu.h>
#include <wx/frame.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class wxBrowserBase
///////////////////////////////////////////////////////////////////////////////
class wxBrowserBase : public wxFrame
{
    private:
    protected:
        wxButton* m_back;
        wxButton* m_forward;
        wxButton* m_home;
        wxButton* m_refresh;
        wxTextCtrl* m_urlbar;
        wxGauge* m_gauge1;
        wxAuiNotebook* m_auinotebook1;
        wxStatusBar* m_statusBar1;
        wxMenuBar* m_menubar1;
        wxMenu* m_menu_file;
        // Virtual event handlers, override them in your derived class
        virtual void OnBack( wxCommandEvent& event ) { event.Skip(); }
        virtual void OnForward( wxCommandEvent& event ) { event.Skip(); }
        virtual void OnHome( wxCommandEvent& event ) { event.Skip(); }
        virtual void OnReload( wxCommandEvent& event ) { event.Skip(); }
        virtual void m_urlbarOnLeftUp( wxMouseEvent& event ) { event.Skip(); }
        virtual void m_urlbarOnSetFocus( wxFocusEvent& event ) { event.Skip(); }
        virtual void OnUrlEnter( wxCommandEvent& event ) { event.Skip(); }
        virtual void OnPageChanged( wxAuiNotebookEvent& event ) { event.Skip(); }
        virtual void OnPageChanging( wxAuiNotebookEvent& event ) { event.Skip(); }
        virtual void OnPageClose( wxAuiNotebookEvent& event ) { event.Skip(); }
        virtual void OnPageClosed( wxAuiNotebookEvent& event ) { event.Skip(); }
        virtual void OnNewTab( wxCommandEvent& event ) { event.Skip(); }
    public:
        wxBrowserBase( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("wxBrowser"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 800,600 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
        ~wxBrowserBase();
};
src/handlers/CurlHttpHandler.h
New file
@@ -0,0 +1,67 @@
#ifndef CURL_HTTP_HANDLER_H
#define CURL_HTTP_HANDLER_H
#include <curl/curl.h>
#include <map>
#include <wx/filesys.h>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/webview.h>
class CurlHttpHandler : public wxWebViewHandler {
public:
  CurlHttpHandler() : wxWebViewHandler("phttp") {}
  wxFSFile *GetFile(const wxString &uri) override {
    wxLogMessage("Curl HTTP Handler: Loading %s", uri);
    // Check cache first
    if (cache.find(uri) != cache.end()) {
      return new wxFSFile(
          new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
          "text/html", wxEmptyString, wxDateTime::Now());
      new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
          "text/html";
    }
    // Fetch content using curl
    std::string content = FetchURL(uri.ToStdString());
    if (content.empty()) {
      wxLogError("Failed to load %s", uri);
      return nullptr;
    }
    // Cache the response
    std::vector<char> buffer(content.begin(), content.end());
    cache[uri] = buffer;
    return new wxFSFile(
        new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
        "text/html", wxEmptyString, wxDateTime::Now());
  }
private:
  static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
                              std::string *output) {
    size_t totalSize = size * nmemb;
    output->append((char *)contents, totalSize);
    return totalSize;
  }
  std::string FetchURL(const std::string &url) {
    CURL *curl = curl_easy_init();
    std::string response;
    if (curl) {
      curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
      curl_easy_perform(curl);
      curl_easy_cleanup(curl);
    }
    return response;
  }
  std::map<wxString, std::vector<char>> cache;
};
#endif // CURL_HTTP_HANDLER_H
src/handlers/CurlHttpsHandler.h
New file
@@ -0,0 +1,87 @@
#ifndef CURL_HTTPS_HANDLER_H
#define CURL_HTTPS_HANDLER_H
#include <curl/curl.h>
#include <iostream>
#include <map>
#include <wx/filesys.h>
#include <wx/log.h>
#include <wx/mstream.h>
#include <wx/webview.h>
class CurlHttpsHandler : public wxWebViewHandler {
public:
  CurlHttpsHandler() : wxWebViewHandler("phttps") {}
  wxFSFile *GetFile(const wxString &url) override {
    wxString uri = url.SubString(1, url.length() - 1);
    std::cout << "CurlHttpsHandler::GetFile called with uri: " << uri
              << std::endl;
    // Check cache first
    if (cache.find(uri) != cache.end()) {
      return new wxFSFile(
          new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
          "text/html", wxEmptyString, wxDateTime::Now());
      new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
          "text/html";
    }
    // Fetch content using curl
    std::pair<std::string, std::string> response = FetchURL(uri.ToStdString());
    if (response.second.empty()) {
      wxLogError("Failed to load %s", response.first);
      return nullptr;
    }
    auto content = response.second;
    std::string finalUrl = response.first;
    uri = wxString::FromUTF8(finalUrl.c_str());
    // Cache the response
    std::vector<char> buffer(content.begin(), content.end());
    cache[uri] = buffer;
    return new wxFSFile(
        new wxMemoryInputStream(cache[uri].data(), cache[uri].size()), uri,
        "text/html", wxEmptyString, wxDateTime::Now());
  }
private:
  static size_t WriteCallback(void *contents, size_t size, size_t nmemb,
                              std::string *output) {
    size_t totalSize = size * nmemb;
    output->append((char *)contents, totalSize);
    return totalSize;
  }
  std::pair<std::string, std::string> FetchURL(const std::string &url) {
    CURL *curl = curl_easy_init();
    std::string response;
    std::string finalUrl;
    if (curl) {
      curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
                       1L);
      if (curl_easy_perform(curl) == CURLE_OK) {
        char *effectiveUrl = nullptr;
        curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effectiveUrl);
        if (effectiveUrl) {
          finalUrl = effectiveUrl;
        }
      }
      curl_easy_cleanup(curl);
    }
    return {finalUrl, response};
  }
  std::map<wxString, std::vector<char>> cache;
};
#endif // CURL_HTTPS_HANDLER_H
src/handlers/WebViewHandler.h
New file
@@ -0,0 +1,107 @@
#ifndef WEBVIEWHANDLER_H
#define WEBVIEWHANDLER_H
#include <iostream>
#include <wx/log.h>
#include <wx/webview.h>
class WebViewHandler {
public:
  enum class CallbackType {
    OnNavigating,
    OnNavigated,
    OnLoaded,
    OnError,
    OnNewWindow,
    OnTitleChanged,
  };
  typedef std::function<void(CallbackType, const wxString, WebViewHandler *)>
      callback_t;
  WebViewHandler(wxWebView *webView, callback_t clb = nullptr)
      : m_webView(webView), callback(clb) {
    if (m_webView) {
      m_webView->Bind(wxEVT_WEBVIEW_NAVIGATING, &WebViewHandler::OnNavigating,
                      this);
      m_webView->Bind(wxEVT_WEBVIEW_NAVIGATED, &WebViewHandler::OnNavigated,
                      this);
      m_webView->Bind(wxEVT_WEBVIEW_LOADED, &WebViewHandler::OnLoaded, this);
      m_webView->Bind(wxEVT_WEBVIEW_ERROR, &WebViewHandler::OnError, this);
      m_webView->Bind(wxEVT_WEBVIEW_NEWWINDOW, &WebViewHandler::OnNewWindow,
                      this);
      m_webView->Bind(wxEVT_WEBVIEW_TITLE_CHANGED,
                      &WebViewHandler::OnTitleChanged, this);
    }
  }
  virtual ~WebViewHandler() {
    if (m_webView) {
      m_webView->Unbind(wxEVT_WEBVIEW_NAVIGATING, &WebViewHandler::OnNavigating,
                        this);
      m_webView->Unbind(wxEVT_WEBVIEW_NAVIGATED, &WebViewHandler::OnNavigated,
                        this);
      m_webView->Unbind(wxEVT_WEBVIEW_LOADED, &WebViewHandler::OnLoaded, this);
      m_webView->Unbind(wxEVT_WEBVIEW_ERROR, &WebViewHandler::OnError, this);
      m_webView->Unbind(wxEVT_WEBVIEW_NEWWINDOW, &WebViewHandler::OnNewWindow,
                        this);
    }
  }
  wxWebView *GetwebView() { return m_webView; }
protected:
  virtual void OnNavigating(wxWebViewEvent &event) {
    if (this->callback) {
      this->callback(CallbackType::OnNavigating, event.GetURL(), this);
    }
    std::cout << "Navigating to: " << event.GetURL() << std::endl;
  }
  virtual void OnTitleChanged(wxWebViewEvent &event) {
    wxString title = event.GetString();
    if (title.IsEmpty()) {
      title = m_webView->GetCurrentTitle();
    }
    if (title.IsEmpty()) {
      return;
    }
    if (this->callback) {
      this->callback(CallbackType::OnTitleChanged, title, this);
    }
    std::cout << "Title changed: " << title << std::endl;
  }
  virtual void OnNavigated(wxWebViewEvent &event) {
    if (this->callback) {
      this->callback(CallbackType::OnNavigated, event.GetURL(), this);
    }
    std::cout << "Navigating to: " << event.GetURL() << std::endl;
  }
  virtual void OnLoaded(wxWebViewEvent &event) {
    if (this->callback) {
      this->callback(CallbackType::OnLoaded, event.GetURL(), this);
    }
    std::cout << "Page loaded: " << event.GetURL() << std::endl;
  }
  virtual void OnError(wxWebViewEvent &event) {
    if (this->callback) {
      this->callback(CallbackType::OnError, event.GetString(), this);
    }
    std::cout << "Error loading page: " << event.GetString() << std::endl;
  }
  virtual void OnNewWindow(wxWebViewEvent &event) {
    if (this->callback) {
      this->callback(CallbackType::OnNewWindow, event.GetURL(), this);
    }
    std::cout << "New window requested: " << event.GetURL() << std::endl;
  }
private:
  wxWebView *m_webView;
  callback_t callback = nullptr;
};
#endif // WEBVIEWHANDLER_H
src/main.cpp
New file
@@ -0,0 +1,4 @@
#include "BrowserApp.h"
#include <wx/wx.h>
wxIMPLEMENT_APP(BrowserApp);