Merge branch 'dk_desktop'

This commit is contained in:
Lukas Matena 2024-12-13 13:58:41 +01:00
commit c1c49c2d6f
7 changed files with 115 additions and 14 deletions

View File

@ -59,10 +59,10 @@ std::optional<std::string> get_env(std::string_view key) {
return std::string{result}; return std::string{result};
} }
namespace Slic3r { namespace {
std::optional<boost::filesystem::path> get_home_config_dir() { std::optional<boost::filesystem::path> get_home_dir(const std::string& subfolder) {
if (auto result{get_env("HOME")}) { if (auto result{get_env("HOME")}) {
return *result + "/.config"; return *result + subfolder;
} else { } else {
std::optional<std::string> user_name{get_env("USER")}; std::optional<std::string> user_name{get_env("USER")};
if (!user_name) { if (!user_name) {
@ -78,13 +78,23 @@ std::optional<boost::filesystem::path> get_home_config_dir() {
who = getpwuid(getuid()); who = getpwuid(getuid());
} }
if (who) { if (who) {
return std::string{who->pw_dir} + "/.config"; return std::string{who->pw_dir} + subfolder;
} }
} }
return std::nullopt; return std::nullopt;
} }
} }
namespace Slic3r {
std::optional<boost::filesystem::path> get_home_config_dir() {
return get_home_dir("/.config");
}
std::optional<boost::filesystem::path> get_home_local_dir() {
return get_home_dir("/.local");
}
}
std::string GetDataDir() std::string GetDataDir()
{ {
if (auto result{get_env("XDG_CONFIG_HOME")}) { if (auto result{get_env("XDG_CONFIG_HOME")}) {

View File

@ -14,6 +14,7 @@ namespace Slic3r {
// Only defined on linux. // Only defined on linux.
std::optional<boost::filesystem::path> get_home_config_dir(); std::optional<boost::filesystem::path> get_home_config_dir();
std::optional<boost::filesystem::path> get_home_local_dir();
std::string get_default_datadir(); std::string get_default_datadir();

View File

@ -14,10 +14,10 @@
#include "libslic3r/Utils.hpp" #include "libslic3r/Utils.hpp"
#include "libslic3r/Platform.hpp" #include "libslic3r/Platform.hpp"
#include "libslic3r/Config.hpp" #include "libslic3r/Config.hpp"
#include "libslic3r/Utils/DirectoriesUtils.hpp"
#include <boost/nowide/fstream.hpp> // IWYU pragma: keep #include <boost/nowide/fstream.hpp> // IWYU pragma: keep
#include <boost/nowide/convert.hpp> #include <boost/nowide/convert.hpp>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/dll/runtime_symbol_info.hpp> #include <boost/dll/runtime_symbol_info.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
@ -224,6 +224,7 @@ bool create_desktop_file(const std::string& path, const std::string& data)
// methods that actually do / undo desktop integration. Static to be accesible from anywhere. // methods that actually do / undo desktop integration. Static to be accesible from anywhere.
bool DesktopIntegrationDialog::is_integrated() bool DesktopIntegrationDialog::is_integrated()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
const AppConfig *app_config = wxGetApp().app_config; const AppConfig *app_config = wxGetApp().app_config;
std::string path(app_config->get("desktop_integration_app_path")); std::string path(app_config->get("desktop_integration_app_path"));
BOOST_LOG_TRIVIAL(debug) << "Desktop integration desktop file path: " << path; BOOST_LOG_TRIVIAL(debug) << "Desktop integration desktop file path: " << path;
@ -237,10 +238,12 @@ bool DesktopIntegrationDialog::is_integrated()
} }
bool DesktopIntegrationDialog::integration_possible() bool DesktopIntegrationDialog::integration_possible()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
return true; return true;
} }
void DesktopIntegrationDialog::perform_desktop_integration() void DesktopIntegrationDialog::perform_desktop_integration()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
BOOST_LOG_TRIVIAL(debug) << "performing desktop integration."; BOOST_LOG_TRIVIAL(debug) << "performing desktop integration.";
// Path to appimage // Path to appimage
const char *appimage_env = std::getenv("APPIMAGE"); const char *appimage_env = std::getenv("APPIMAGE");
@ -446,8 +449,9 @@ void DesktopIntegrationDialog::perform_desktop_integration()
} }
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess); wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess);
} }
void DesktopIntegrationDialog::undo_desktop_intgration() void DesktopIntegrationDialog::undo_desktop_integration()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
const AppConfig *app_config = wxGetApp().app_config; const AppConfig *app_config = wxGetApp().app_config;
// slicer .desktop // slicer .desktop
std::string path = std::string(app_config->get("desktop_integration_app_path")); std::string path = std::string(app_config->get("desktop_integration_app_path"));
@ -634,6 +638,7 @@ void DesktopIntegrationDialog::perform_downloader_desktop_integration()
} }
void DesktopIntegrationDialog::undo_downloader_registration() void DesktopIntegrationDialog::undo_downloader_registration()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
const AppConfig *app_config = wxGetApp().app_config; const AppConfig *app_config = wxGetApp().app_config;
std::string path = std::string(app_config->get("desktop_integration_URL_path")); std::string path = std::string(app_config->get("desktop_integration_URL_path"));
if (!path.empty()) { if (!path.empty()) {
@ -644,6 +649,7 @@ void DesktopIntegrationDialog::undo_downloader_registration()
} }
void DesktopIntegrationDialog::undo_downloader_registration_rigid() void DesktopIntegrationDialog::undo_downloader_registration_rigid()
{ {
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__;
// Try ro find any PrusaSlicerURLProtocol.desktop files including alpha and beta and get rid of them // 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. // $XDG_DATA_HOME defines the base directory relative to which user specific data files should be stored.
@ -655,7 +661,7 @@ void DesktopIntegrationDialog::undo_downloader_registration_rigid()
target_candidates.emplace_back(GUI::into_u8(wxFileName::GetHomeDir()) + "/.local/share"); 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_HOME", target_candidates);
resolve_path_from_var("XDG_DATA_DIRS", target_candidates); resolve_path_from_var("XDG_DATA_DIRS", target_candidates);
for (const std::string cand : target_candidates) { for (const std::string& cand : target_candidates) {
boost::filesystem::path apps_path = get_existing_dir(cand, "applications"); boost::filesystem::path apps_path = get_existing_dir(cand, "applications");
if (apps_path.empty()) { if (apps_path.empty()) {
continue; continue;
@ -675,6 +681,57 @@ void DesktopIntegrationDialog::undo_downloader_registration_rigid()
} }
} }
void DesktopIntegrationDialog::find_all_desktop_files(std::vector<boost::filesystem::path>& results)
{
// Try ro find any PrusaSlicer.desktop and PrusaSlicerGcodeViewer.desktop and PrusaSlicerURLProtocol.desktop files including alpha and beta
// For regular apps (f.e. appimage) this is true:
// $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.
// But flatpak resets XDG_DATA_HOME and XDG_DATA_DIRS, so we do not look into them
// Lets look into $HOME/.local/share, /usr/local/share/, /usr/share/
std::vector<std::string> target_candidates;
if (auto home_config_dir = Slic3r::get_home_local_dir(); home_config_dir) {
target_candidates.emplace_back((*home_config_dir).string() + "/share");
}
target_candidates.emplace_back("usr/local/share/");
target_candidates.emplace_back("usr/share/");
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& filename : {"PrusaSlicer","PrusaSlicerGcodeViewer","PrusaSlicerURLProtocol"}) {
for (const std::string& suffix : {"" , "-beta", "-alpha", "_beta", "_alpha"}) {
boost::filesystem::path file_path = apps_path / GUI::format("%1%%2%.desktop", filename, suffix);
boost::system::error_code ec;
if (!boost::filesystem::exists(file_path, ec) || ec) {
continue;
}
BOOST_LOG_TRIVIAL(debug) << "Desktop File found: " << file_path;
results.emplace_back(std::move(file_path));
}
}
}
}
void DesktopIntegrationDialog::remove_desktop_file_list(const std::vector<boost::filesystem::path>& list, std::vector<boost::filesystem::path>& fails)
{
for (const boost::filesystem::path& entry : list) {
boost::system::error_code ec;
if (!boost::filesystem::remove(entry, ec) || ec) {
BOOST_LOG_TRIVIAL(error) << "Failed to remove file " << entry << " ec: " << ec.message();
fails.emplace_back(entry);
continue;
}
BOOST_LOG_TRIVIAL(info) << "Desktop File removed: " << entry;
}
}
DesktopIntegrationDialog::DesktopIntegrationDialog(wxWindow *parent) DesktopIntegrationDialog::DesktopIntegrationDialog(wxWindow *parent)
: wxDialog(parent, wxID_ANY, _(L("Desktop Integration")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER) : wxDialog(parent, wxID_ANY, _(L("Desktop Integration")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
{ {
@ -705,7 +762,7 @@ DesktopIntegrationDialog::DesktopIntegrationDialog(wxWindow *parent)
if (can_undo){ if (can_undo){
wxButton *btn_undo = new wxButton(this, wxID_ANY, _L("Undo")); wxButton *btn_undo = new wxButton(this, wxID_ANY, _L("Undo"));
btn_szr->Add(btn_undo, 0, wxALL, 10); btn_szr->Add(btn_undo, 0, wxALL, 10);
btn_undo->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { DesktopIntegrationDialog::undo_desktop_intgration(); EndModal(wxID_ANY); }); btn_undo->Bind(wxEVT_BUTTON, [this](wxCommandEvent &) { DesktopIntegrationDialog::undo_desktop_integration(); EndModal(wxID_ANY); });
} }
wxButton *btn_cancel = new wxButton(this, wxID_ANY, _L("Cancel")); wxButton *btn_cancel = new wxButton(this, wxID_ANY, _L("Cancel"));
btn_szr->Add(btn_cancel, 0, wxALL, 10); btn_szr->Add(btn_cancel, 0, wxALL, 10);
@ -718,7 +775,6 @@ DesktopIntegrationDialog::DesktopIntegrationDialog(wxWindow *parent)
DesktopIntegrationDialog::~DesktopIntegrationDialog() DesktopIntegrationDialog::~DesktopIntegrationDialog()
{ {
} }
} // namespace GUI } // namespace GUI

View File

@ -7,6 +7,8 @@
#define slic3r_DesktopIntegrationDialog_hpp_ #define slic3r_DesktopIntegrationDialog_hpp_
#include <wx/dialog.h> #include <wx/dialog.h>
#include <boost/filesystem.hpp>
namespace Slic3r { namespace Slic3r {
namespace GUI { namespace GUI {
@ -35,13 +37,13 @@ public:
// Regiters PrusaSlicer to start on prusaslicer:// URL // Regiters PrusaSlicer to start on prusaslicer:// URL
static void perform_desktop_integration(); static void perform_desktop_integration();
// Deletes Desktop files and icons for both PrusaSlicer and GcodeViewer at paths stored in App Config. // Deletes Desktop files and icons for both PrusaSlicer and GcodeViewer at paths stored in App Config.
static void undo_desktop_intgration(); static void undo_desktop_integration();
static void perform_downloader_desktop_integration(); static void perform_downloader_desktop_integration();
static void undo_downloader_registration(); static void undo_downloader_registration();
static void undo_downloader_registration_rigid(); static void undo_downloader_registration_rigid();
private: static void find_all_desktop_files(std::vector<boost::filesystem::path>& results);
static void remove_desktop_file_list(const std::vector<boost::filesystem::path>& list, std::vector<boost::filesystem::path>& fails);
}; };
} // namespace GUI } // namespace GUI
} // namespace Slic3r } // namespace Slic3r

View File

@ -1311,6 +1311,31 @@ static int get_app_font_pt_size(const AppConfig* app_config)
return (font_pt_size > max_font_pt_size) ? max_font_pt_size : font_pt_size; return (font_pt_size > max_font_pt_size) ? max_font_pt_size : font_pt_size;
} }
#if defined(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
void GUI_App::remove_desktop_files_dialog()
{
// Find all old existing desktop file
std::vector<boost::filesystem::path> found_desktop_files;
DesktopIntegrationDialog::find_all_desktop_files(found_desktop_files);
if(found_desktop_files.empty()) {
return;
}
// Delete files.
std::vector<boost::filesystem::path> fails;
DesktopIntegrationDialog::remove_desktop_file_list(found_desktop_files, fails);
if (fails.empty()) {
return;
}
// Inform about fails.
std::string text = "Failed to remove desktop files:";
text += "\n";
for (const boost::filesystem::path& entry : fails) {
text += GUI::format("%1%\n",entry.string());
}
BOOST_LOG_TRIVIAL(error) << text;
}
#endif //(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
bool GUI_App::on_init_inner() bool GUI_App::on_init_inner()
{ {
// TODO: remove this when all asserts are gone. // TODO: remove this when all asserts are gone.
@ -1569,6 +1594,10 @@ bool GUI_App::on_init_inner()
// Call this check only after appconfig was loaded to mainframe, otherwise there will be duplicity error. // Call this check only after appconfig was loaded to mainframe, otherwise there will be duplicity error.
legacy_app_config_vendor_check(); legacy_app_config_vendor_check();
#if defined(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
remove_desktop_files_dialog();
#endif //(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
sidebar().obj_list()->init_objects(); // propagate model objects to object list sidebar().obj_list()->init_objects(); // propagate model objects to object list
update_mode(); // mode sizer doesn't exist anymore, so we came update mode here, before load_current_presets update_mode(); // mode sizer doesn't exist anymore, so we came update mode here, before load_current_presets
SetTopWindow(mainframe); SetTopWindow(mainframe);
@ -2723,7 +2752,7 @@ wxMenu* GUI_App::get_config_menu(MainFrame* main_frame)
#ifdef __linux__ #ifdef __linux__
case ConfigMenuDesktopIntegration: case ConfigMenuDesktopIntegration:
show_desktop_integration_dialog(); show_desktop_integration_dialog();
break; break;
#endif #endif
case ConfigMenuTakeSnapshot: case ConfigMenuTakeSnapshot:
// Take a configuration snapshot. // Take a configuration snapshot.

View File

@ -453,6 +453,9 @@ private:
void app_updater(bool from_user); void app_updater(bool from_user);
// inititate read of version file online in separate thread // inititate read of version file online in separate thread
void app_version_check(bool from_user); void app_version_check(bool from_user);
#if defined(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
void remove_desktop_files_dialog();
#endif //(__linux__) && !defined(SLIC3R_DESKTOP_INTEGRATION)
bool m_wifi_config_dialog_shown { false }; bool m_wifi_config_dialog_shown { false };
bool m_wifi_config_dialog_was_declined { false }; bool m_wifi_config_dialog_was_declined { false };

View File

@ -637,7 +637,7 @@ void PreferencesDialog::build()
L("Show \"Log in\" button in application top bar"), L("Show \"Log in\" button in application top bar"),
L("If enabled, PrusaSlicer will show up \"Log in\" button in application top bar."), L("If enabled, PrusaSlicer will show up \"Log in\" button in application top bar."),
app_config->get_bool("show_login_button")); app_config->get_bool("show_login_button"));
append_bool_option(m_optgroup_other, "downloader_url_registered", append_bool_option(m_optgroup_other, "downloader_url_registered",
L("Allow downloads from Printables.com"), L("Allow downloads from Printables.com"),
L("If enabled, PrusaSlicer will be allowed to download from Printables.com"), L("If enabled, PrusaSlicer will be allowed to download from Printables.com"),