diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index fbe9fbaa51..9a0bd956e6 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -5664,6 +5664,10 @@ CLIMiscConfigDef::CLIMiscConfigDef() "or an existing PrusaSlicer window is activated. " "Overrides the \"single_instance\" configuration value from application preferences."); + def = this->add("single_instance_on_url", coBool); + def->label = L("Single instance mode for prusaslicer url"); + def->tooltip = L("Works as single_instance but only if prusaslicer url is present."); + def = this->add("datadir", coString); def->label = L("Data directory"); def->tooltip = L("Load and store settings at the given directory. This is useful for maintaining different profiles or including configurations from a network storage."); diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index 59ea6386aa..7dec1da12a 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -1718,7 +1718,7 @@ bool PageDownloader::on_finish_downloader() const bool DownloaderUtils::Worker::perform_registration_linux = false; #endif // __linux__ -bool DownloaderUtils::Worker::perform_register(const std::string& path) +bool DownloaderUtils::Worker::perform_download_register(const std::string& path) { boost::filesystem::path aux_dest (path); boost::system::error_code ec; @@ -1734,6 +1734,10 @@ bool DownloaderUtils::Worker::perform_register(const std::string& path) } BOOST_LOG_TRIVIAL(info) << "Downloader registration: Directory for downloads: " << chosen_dest.string(); wxGetApp().app_config->set("url_downloader_dest", chosen_dest.string()); + return perform_url_register(); +} +bool DownloaderUtils::Worker::perform_url_register() +{ #ifdef _WIN32 // Registry key creation for "prusaslicer://" URL @@ -1793,12 +1797,12 @@ bool DownloaderUtils::Worker::on_finish() { BOOST_LOG_TRIVIAL(debug) << "PageDownloader::on_finish_downloader ac_value " << ac_value << " downloader_checked " << downloader_checked; if (ac_value && downloader_checked) { // already registered but we need to do it again - if (!perform_register(GUI::into_u8(path_name()))) + if (!perform_download_register(GUI::into_u8(path_name()))) return false; app_config->set("downloader_url_registered", "1"); } else if (!ac_value && downloader_checked) { // register - if (!perform_register(GUI::into_u8(path_name()))) + if (!perform_download_register(GUI::into_u8(path_name()))) return false; app_config->set("downloader_url_registered", "1"); } else if (ac_value && !downloader_checked) { diff --git a/src/slic3r/GUI/ConfigWizard.hpp b/src/slic3r/GUI/ConfigWizard.hpp index ba39d531ac..cc9d36d806 100644 --- a/src/slic3r/GUI/ConfigWizard.hpp +++ b/src/slic3r/GUI/ConfigWizard.hpp @@ -52,7 +52,8 @@ namespace DownloaderUtils { void set_path_name(const std::string& name); bool on_finish(); - static bool perform_register(const std::string& path); + static bool perform_download_register(const std::string& path); + static bool perform_url_register(); #ifdef __linux__ static bool perform_registration_linux; #endif // __linux__ diff --git a/src/slic3r/GUI/ConfigWizardWebViewPage.cpp b/src/slic3r/GUI/ConfigWizardWebViewPage.cpp index 87e7f6ccbe..0023707813 100644 --- a/src/slic3r/GUI/ConfigWizardWebViewPage.cpp +++ b/src/slic3r/GUI/ConfigWizardWebViewPage.cpp @@ -6,9 +6,11 @@ #include "Plater.hpp" #include "slic3r/GUI/I18N.hpp" #include "format.hpp" - +#include "Event.hpp" #include +wxDEFINE_EVENT(EVT_OPEN_EXTERNAL_LOGIN_WIZARD, wxCommandEvent); + namespace Slic3r { namespace GUI { wxDEFINE_EVENT(EVT_LOGIN_VIA_WIZARD, Event); @@ -23,7 +25,7 @@ ConfigWizardWebViewPage::ConfigWizardWebViewPage(ConfigWizard *parent) // Create the webview m_browser_sizer = new wxBoxSizer(wxHORIZONTAL); - m_browser = WebView::CreateWebView(this, p_user_account->get_login_redirect_url(), {}); + m_browser = WebView::CreateWebView(this, p_user_account->generate_login_redirect_url(), {}); if (!m_browser) { // TRN Config wizard page with a log in page. wxStaticText* fail_text = new wxStaticText(this, wxID_ANY, _L("Failed to load a web browser. Logging in is not possible in the moment.")); @@ -124,7 +126,17 @@ void ConfigWizardWebViewPage::on_navigation_request(wxWebViewEvent &evt) evt.Veto(); m_vetoed = true; wxPostEvent(wxGetApp().plater(), Event(EVT_LOGIN_VIA_WIZARD, into_u8(url))); + } else if (url.Find("accounts.google.com") != wxString::npos + || url.Find("appleid.apple.com") != wxString::npos + || url.Find("facebook.com") != wxString::npos) + { + auto& sc = Utils::ServiceConfig::instance(); + if (!m_evt_sent && !url.starts_with(GUI::from_u8(sc.account_url()))) { + wxCommandEvent evt(EVT_OPEN_EXTERNAL_LOGIN_WIZARD); + evt.SetString(url); + wxPostEvent(wxGetApp().plater(), evt); + m_evt_sent = true; + } } } - }} // namespace Slic3r::GUI \ No newline at end of file diff --git a/src/slic3r/GUI/ConfigWizardWebViewPage.hpp b/src/slic3r/GUI/ConfigWizardWebViewPage.hpp index 8ad6638063..2a873de805 100644 --- a/src/slic3r/GUI/ConfigWizardWebViewPage.hpp +++ b/src/slic3r/GUI/ConfigWizardWebViewPage.hpp @@ -2,15 +2,18 @@ #define slic3r_ConfigWizardWebViewPage_hpp_ #include "ConfigWizard_private.hpp" -#include "Event.hpp" +#include class wxWebView; class wxWebViewEvent; +wxDECLARE_EVENT(EVT_OPEN_EXTERNAL_LOGIN_WIZARD, wxCommandEvent); + namespace Slic3r { namespace GUI { wxDECLARE_EVENT(EVT_LOGIN_VIA_WIZARD, Event); + /* struct ConfigWizardPage: wxPanel { @@ -61,6 +64,7 @@ private: wxStaticText *m_text{nullptr}; bool m_load_error_page{false}; bool m_vetoed{false}; + bool m_evt_sent{false}; }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.cpp b/src/slic3r/GUI/DesktopIntegrationDialog.cpp index d8f3dc025b..2ca450bf9c 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.cpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.cpp @@ -139,20 +139,35 @@ bool contains_path_dir(const std::string& p, const std::string& dir_name) if (p.empty() || dir_name.empty()) return false; boost::filesystem::path path(p + (p[p.size()-1] == '/' ? "" : "/") + dir_name); - if (boost::filesystem::exists(path) && boost::filesystem::is_directory(path)) { + boost::system::error_code ec; + if (boost::filesystem::exists(path, ec) && !ec) { //BOOST_LOG_TRIVIAL(debug) << path.string() << " " << std::oct << boost::filesystem::status(path).permissions(); - return true; //boost::filesystem::status(path).permissions() & boost::filesystem::owner_write; + return boost::filesystem::is_directory(path); //boost::filesystem::status(path).permissions() & boost::filesystem::owner_write; } else BOOST_LOG_TRIVIAL(debug) << path.string() << " doesnt exists"; return false; } + +boost::filesystem::path get_existing_dir(const std::string& sub, const std::string& dir_name) +{ + assert(!p.empty() && !dir_name.empty()); + boost::filesystem::path path = boost::filesystem::path(sub) / dir_name; + boost::system::error_code ec; + if (!boost::filesystem::exists(path, ec) || ec) { + return boost::filesystem::path(); + } + if (!boost::filesystem::is_directory(path, ec) || ec) { + return boost::filesystem::path(); + } + return path; +} // Creates directory in path if not exists yet void create_dir(const boost::filesystem::path& path) { - if (boost::filesystem::exists(path)) + boost::system::error_code ec; + if (boost::filesystem::exists(path, ec) && !ec) return; BOOST_LOG_TRIVIAL(debug)<< "creating " << path.string(); - boost::system::error_code ec; boost::filesystem::create_directory(path, ec); if (ec) BOOST_LOG_TRIVIAL(error)<< "create directory failed: " << ec.message(); @@ -514,12 +529,12 @@ void DesktopIntegrationDialog::perform_downloader_desktop_integration() std::string version(SLIC3R_VERSION); if (version.find("alpha") != std::string::npos) { - version_suffix = "-alpha"; + version_suffix = "_alpha"; name_suffix = " - alpha"; } else if (version.find("beta") != std::string::npos) { - version_suffix = "-beta"; + version_suffix = "_beta"; name_suffix = " - beta"; } @@ -627,6 +642,38 @@ void DesktopIntegrationDialog::undo_downloader_registration() } // There is no need to undo xdg-mime default command. It is done automatically when desktop file is deleted. } +void DesktopIntegrationDialog::undo_downloader_registration_rigid() +{ + // Try ro find any PrusaSlicerURLProtocol.desktop files including alpha and beta and get rid of them + + // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored. + // If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share should be used. + // $XDG_DATA_DIRS defines the preference-ordered set of base directories to search for data files in addition to the $XDG_DATA_HOME base directory. + // The directories in $XDG_DATA_DIRS should be seperated with a colon ':'. + // If $XDG_DATA_DIRS is either not set or empty, a value equal to /usr/local/share/:/usr/share/ should be used. + std::vectortarget_candidates; + target_candidates.emplace_back(GUI::into_u8(wxFileName::GetHomeDir()) + "/.local/share"); + resolve_path_from_var("XDG_DATA_HOME", target_candidates); + resolve_path_from_var("XDG_DATA_DIRS", target_candidates); + for (const std::string cand : target_candidates) { + boost::filesystem::path apps_path = get_existing_dir(cand, "applications"); + if (apps_path.empty()) { + continue; + } + for (const std::string& suffix : {"" , "-beta", "-alpha" , "_beta", "_alpha"}) { + boost::filesystem::path file_path = apps_path / GUI::format("PrusaSlicerURLProtocol%1%.desktop", suffix); + boost::system::error_code ec; + if (!boost::filesystem::exists(file_path, ec) || ec) { + continue; + } + if (!boost::filesystem::remove(file_path, ec) || ec) { + BOOST_LOG_TRIVIAL(error) << "Failed to remove file " << file_path << " ec: " << ec.message(); + continue; + } + BOOST_LOG_TRIVIAL(info) << "Desktop File removed: " << file_path; + } + } +} DesktopIntegrationDialog::DesktopIntegrationDialog(wxWindow *parent) : wxDialog(parent, wxID_ANY, _(L("Desktop Integration")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) diff --git a/src/slic3r/GUI/DesktopIntegrationDialog.hpp b/src/slic3r/GUI/DesktopIntegrationDialog.hpp index 4c2263d0fd..c26ad6b8d4 100644 --- a/src/slic3r/GUI/DesktopIntegrationDialog.hpp +++ b/src/slic3r/GUI/DesktopIntegrationDialog.hpp @@ -39,6 +39,7 @@ public: static void perform_downloader_desktop_integration(); static void undo_downloader_registration(); + static void undo_downloader_registration_rigid(); private: }; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 1ef8b24ffc..905478207e 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3337,7 +3337,7 @@ void GUI_App::show_downloader_registration_dialog() , true, wxYES_NO); if (msg.ShowModal() == wxID_YES) { auto downloader_worker = new DownloaderUtils::Worker(nullptr); - downloader_worker->perform_register(app_config->get("url_downloader_dest")); + downloader_worker->perform_download_register(app_config->get("url_downloader_dest")); #if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION) if (DownloaderUtils::Worker::perform_registration_linux) DesktopIntegrationDialog::perform_downloader_desktop_integration(); diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp index ce96c1c42f..882e2e3259 100644 --- a/src/slic3r/GUI/InstanceCheck.cpp +++ b/src/slic3r/GUI/InstanceCheck.cpp @@ -69,18 +69,29 @@ namespace instance_check_internal //if (argc < 2) // return ret; std::vector arguments { argv[0] }; + bool send_if_url = false; + bool has_url = false; for (int i = 1; i < argc; ++i) { const std::string token = argv[i]; + if (token.find("prusaslicer://") == 0) { + BOOST_LOG_TRIVIAL(info) << "url found: " << token; + has_url = true; + } // Processing of boolean command line arguments shall match DynamicConfig::read_cli(). if (token == "--single-instance") ret.should_send = true; else if (token == "--no-single-instance") ret.should_send = false; + else if (token == "--single-instance-on-url") + send_if_url = true; else arguments.emplace_back(token); } + if (send_if_url && has_url) { + ret.should_send = true; + } ret.cl_string = escape_strings_cstyle(arguments); - BOOST_LOG_TRIVIAL(debug) << "single instance: " << + BOOST_LOG_TRIVIAL(info) << "single instance: " << (ret.should_send.has_value() ? (*ret.should_send ? "true" : "false") : "undefined") << ". other params: " << ret.cl_string; return ret; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9c70d60074..3ac107988e 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -126,6 +126,7 @@ #include "UserAccountUtils.hpp" #include "DesktopIntegrationDialog.hpp" #include "WebViewDialog.hpp" +#include "ConfigWizardWebViewPage.hpp" #include "PresetArchiveDatabase.hpp" #ifdef __APPLE__ @@ -272,6 +273,9 @@ struct Plater::priv std::unique_ptr notification_manager; std::unique_ptr user_account; std::unique_ptr preset_archive_database; + // Login dialog needs to be kept somewhere. + // It is created inside evt Bind. But it might be closed from another event. + LoginWebViewDialog* login_dialog { nullptr }; ProjectDirtyStateManager dirty_state; @@ -875,14 +879,43 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) user_account->on_login_code_recieved(evt.data); }); this->q->Bind(EVT_OPEN_PRUSAAUTH, [this](OpenPrusaAuthEvent& evt) { - BOOST_LOG_TRIVIAL(info) << "open login browser: " << evt.data; + BOOST_LOG_TRIVIAL(info) << "open login browser: " << evt.data.first; std::string dialog_msg; - LoginWebViewDialog dialog(this->q, dialog_msg, evt.data); - if (dialog.ShowModal() != wxID_OK) { - return; + login_dialog = new LoginWebViewDialog(this->q, dialog_msg, evt.data.first, this->q); + if (login_dialog->ShowModal() == wxID_OK) { + user_account->on_login_code_recieved(dialog_msg); + } + if (login_dialog != nullptr) { + this->q->RemoveChild(login_dialog); + login_dialog->Destroy(); + login_dialog = nullptr; } - user_account->on_login_code_recieved(dialog_msg); }); + + auto open_external_login = [this](wxCommandEvent& evt){ + DownloaderUtils::Worker::perform_url_register(); +#if defined(__linux__) + // Remove all desktop files registering prusaslicer:// url done by previous versions. + DesktopIntegrationDialog::undo_downloader_registration_rigid(); +#if defined(SLIC3R_DESKTOP_INTEGRATION) + if (DownloaderUtils::Worker::perform_registration_linux) + DesktopIntegrationDialog::perform_downloader_desktop_integration(); +#endif // SLIC3R_DESKTOP_INTEGRATION +#endif // __linux__ + std::string service; + if (evt.GetString().Find("accounts.google.com") != wxString::npos) { + service = "google"; + } else if (evt.GetString().Find("appleid.apple.com") != wxString::npos) { + service = "apple"; + } else if (evt.GetString().Find("facebook.com") != wxString::npos) { + service = "facebook"; + } + wxString url = user_account->get_login_redirect_url(service); + wxGetApp().open_login_browser_with_dialog(into_u8(url), nullptr, false); + }; + + this->q->Bind(EVT_OPEN_EXTERNAL_LOGIN_WIZARD, open_external_login); + this->q->Bind(EVT_OPEN_EXTERNAL_LOGIN, open_external_login); this->q->Bind(EVT_UA_LOGGEDOUT, [this](UserAccountSuccessEvent& evt) { user_account->clear(); @@ -895,12 +928,16 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) sidebar->update_printer_presets_combobox(); wxGetApp().update_wizard_login_page(); this->show_action_buttons(this->ready_to_slice); - - LogoutWebViewDialog dlg(this->q); + // Needed only when using internal web browser to login (which is case of config wizard) + LogoutWebViewDialog dlg(this->q); dlg.ShowModal(); + // }); this->q->Bind(EVT_UA_ID_USER_SUCCESS, [this](UserAccountSuccessEvent& evt) { + if (login_dialog != nullptr) { + login_dialog->EndModal(wxID_CANCEL); + } // There are multiple handlers and we want to notify all evt.Skip(); std::string who = user_account->get_username(); diff --git a/src/slic3r/GUI/UserAccount.hpp b/src/slic3r/GUI/UserAccount.hpp index e38efdd02c..22787f9d7c 100644 --- a/src/slic3r/GUI/UserAccount.hpp +++ b/src/slic3r/GUI/UserAccount.hpp @@ -38,8 +38,9 @@ public: bool is_logged(); void do_login(); void do_logout(); - wxString get_login_redirect_url() { return m_communication->get_login_redirect_url(); } - + wxString generate_login_redirect_url() { return m_communication->generate_login_redirect_url(); } + wxString get_login_redirect_url(const std::string& service = std::string()) { return m_communication->get_login_redirect_url(service); } + void set_remember_session(bool remember); void toggle_remember_session(); bool get_remember_session(); diff --git a/src/slic3r/GUI/UserAccountCommunication.cpp b/src/slic3r/GUI/UserAccountCommunication.cpp index 0a7f261755..27a8dd2957 100644 --- a/src/slic3r/GUI/UserAccountCommunication.cpp +++ b/src/slic3r/GUI/UserAccountCommunication.cpp @@ -321,7 +321,9 @@ void UserAccountCommunication::on_uuid_map_success() } } -wxString UserAccountCommunication::get_login_redirect_url() { +// Generates and stores Code Verifier - second call deletes previous one. +wxString UserAccountCommunication::generate_login_redirect_url() +{ auto& sc = Utils::ServiceConfig::instance(); const std::string AUTH_HOST = sc.account_url(); const std::string CLIENT_ID = client_id(); @@ -335,13 +337,29 @@ wxString UserAccountCommunication::get_login_redirect_url() { BOOST_LOG_TRIVIAL(info) << "code challenge: " << code_challenge; wxString url = GUI::format_wxstr(L"%1%/o/authorize/?embed=1&client_id=%2%&response_type=code&code_challenge=%3%&code_challenge_method=S256&scope=basic_info&redirect_uri=%4%&language=%5%", AUTH_HOST, CLIENT_ID, code_challenge, REDIRECT_URI, language); + return url; +} +wxString UserAccountCommunication::get_login_redirect_url(const std::string& service/* = std::string()*/) const +{ + auto& sc = Utils::ServiceConfig::instance(); + const std::string AUTH_HOST = sc.account_url(); + const std::string CLIENT_ID = client_id(); + const std::string REDIRECT_URI = "prusaslicer://login"; + CodeChalengeGenerator ccg; + std::string code_challenge = ccg.generate_chalenge(m_code_verifier); + wxString language = GUI::wxGetApp().current_language_code(); + language = language.SubString(0, 1); + std::string params = GUI::format("embed=1&client_id=%1%&response_type=code&code_challenge=%2%&code_challenge_method=S256&scope=basic_info&redirect_uri=%3%&language=%4%", CLIENT_ID, code_challenge, REDIRECT_URI, language); + params = Http::url_encode(params); + wxString url = GUI::format_wxstr(L"%1%/login/%2%?next=/o/authorize/?%3%", AUTH_HOST, service, params); return url; } void UserAccountCommunication::login_redirect() { - wxString url = get_login_redirect_url(); - wxQueueEvent(m_evt_handler,new OpenPrusaAuthEvent(GUI::EVT_OPEN_PRUSAAUTH, std::move(url))); + wxString url1 = generate_login_redirect_url(); + wxString url2 = url1 + L"&choose_account=1"; + wxQueueEvent(m_evt_handler,new OpenPrusaAuthEvent(GUI::EVT_OPEN_PRUSAAUTH, {std::move(url1), std::move(url2)})); } bool UserAccountCommunication::is_logged() diff --git a/src/slic3r/GUI/UserAccountCommunication.hpp b/src/slic3r/GUI/UserAccountCommunication.hpp index 623cbf7e6d..f4ec0dbf99 100644 --- a/src/slic3r/GUI/UserAccountCommunication.hpp +++ b/src/slic3r/GUI/UserAccountCommunication.hpp @@ -42,7 +42,10 @@ public: void do_login(); void do_logout(); void do_clear(); - wxString get_login_redirect_url(); + // Generates and stores Code Verifier - second call deletes previous one. + wxString generate_login_redirect_url(); + // Only recreates the url with already existing url (if generate was not called before - url will be faulty) + wxString get_login_redirect_url(const std::string& service = std::string()) const; // Trigger function starts various remote operations void enqueue_connect_status_action(); void enqueue_connect_printer_models_action(); diff --git a/src/slic3r/GUI/UserAccountSession.hpp b/src/slic3r/GUI/UserAccountSession.hpp index 1733ec728f..d540319ab3 100644 --- a/src/slic3r/GUI/UserAccountSession.hpp +++ b/src/slic3r/GUI/UserAccountSession.hpp @@ -14,7 +14,7 @@ namespace Slic3r { namespace GUI { -using OpenPrusaAuthEvent = Event; +using OpenPrusaAuthEvent = Event>; using UserAccountSuccessEvent = Event; using UserAccountFailEvent = Event; using UserAccountTimeEvent = Event; diff --git a/src/slic3r/GUI/WebViewDialog.cpp b/src/slic3r/GUI/WebViewDialog.cpp index 9d5ec17a1f..eac2873152 100644 --- a/src/slic3r/GUI/WebViewDialog.cpp +++ b/src/slic3r/GUI/WebViewDialog.cpp @@ -8,6 +8,7 @@ #include "slic3r/GUI/format.hpp" #include "slic3r/GUI/WebView.hpp" #include "slic3r/GUI/WebViewPlatformUtils.hpp" +#include "slic3r/Utils/ServiceConfig.hpp" #include "slic3r/GUI/MsgDialog.hpp" #include "slic3r/GUI/Field.hpp" @@ -26,6 +27,7 @@ // to set authorization cookie for all WebKit requests to Connect #define AUTH_VIA_FETCH_OVERRIDE 0 +wxDEFINE_EVENT(EVT_OPEN_EXTERNAL_LOGIN, wxCommandEvent); namespace pt = boost::property_tree; @@ -1369,13 +1371,10 @@ void PrinterPickWebViewDialog::on_dpi_changed(const wxRect &suggested_rect) Refresh(); } -LoginWebViewDialog::LoginWebViewDialog(wxWindow *parent, std::string &ret_val, const wxString& url) - : WebViewDialog(parent - , url - , _L("Log in dialog"), - wxSize(50 * wxGetApp().em_unit(), 80 * wxGetApp().em_unit()) - , {}) +LoginWebViewDialog::LoginWebViewDialog(wxWindow *parent, std::string &ret_val, const wxString& url, wxEvtHandler* evt_handler) + : WebViewDialog(parent, url, _L("Log in dialog"), wxSize(50 * wxGetApp().em_unit(), 80 * wxGetApp().em_unit()), {}) , m_ret_val(ret_val) + , p_evt_handler(evt_handler) { Centre(); } @@ -1386,6 +1385,17 @@ void LoginWebViewDialog::on_navigation_request(wxWebViewEvent &evt) evt.Veto(); m_ret_val = into_u8(url); EndModal(wxID_OK); + } else if (url.Find("accounts.google.com") != wxString::npos + || url.Find("appleid.apple.com") != wxString::npos + || url.Find("facebook.com") != wxString::npos) + { + auto& sc = Utils::ServiceConfig::instance(); + if (!m_evt_sent && !url.starts_with(GUI::from_u8(sc.account_url()))) { + wxCommandEvent* evt = new wxCommandEvent(EVT_OPEN_EXTERNAL_LOGIN); + evt->SetString(url); + p_evt_handler->QueueEvent(evt); + m_evt_sent = true; + } } } void LoginWebViewDialog::on_dpi_changed(const wxRect &suggested_rect) diff --git a/src/slic3r/GUI/WebViewDialog.hpp b/src/slic3r/GUI/WebViewDialog.hpp index cc9a76e6f5..92619b0a50 100644 --- a/src/slic3r/GUI/WebViewDialog.hpp +++ b/src/slic3r/GUI/WebViewDialog.hpp @@ -17,6 +17,8 @@ class wxWebView; class wxWebViewEvent; +wxDECLARE_EVENT(EVT_OPEN_EXTERNAL_LOGIN, wxCommandEvent); + namespace Slic3r { namespace GUI { @@ -276,12 +278,14 @@ public: class LoginWebViewDialog : public WebViewDialog { public: - LoginWebViewDialog(wxWindow *parent, std::string &ret_val, const wxString& url); + LoginWebViewDialog(wxWindow *parent, std::string &ret_val, const wxString& url, wxEvtHandler* evt_handler); void on_navigation_request(wxWebViewEvent &evt) override; void on_dpi_changed(const wxRect &suggested_rect) override; private: - std::string &m_ret_val; + std::string& m_ret_val; + wxEvtHandler* p_evt_handler; + bool m_evt_sent{ false }; }; class LogoutWebViewDialog : public WebViewDialog