mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 12:41:20 -06:00 
			
		
		
		
	Desktop integration changes
empty catch block fix internal namespace fix wrong app config var Desktop integration for regular executables cmake option SLIC3R_DESKTOP_INTEGRATION cmake dependent option escape executable path in desktop file by adding /' Error messages instead of notifications.
This commit is contained in:
		
							parent
							
								
									a3b089eceb
								
							
						
					
					
						commit
						12328a74f7
					
				
					 3 changed files with 58 additions and 51 deletions
				
			
		|  | @ -3,6 +3,7 @@ project(PrusaSlicer) | |||
| 
 | ||||
| include("version.inc") | ||||
| include(GNUInstallDirs) | ||||
| include(CMakeDependentOption) | ||||
| 
 | ||||
| set(SLIC3R_RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources") | ||||
| file(TO_NATIVE_PATH "${SLIC3R_RESOURCES_DIR}" SLIC3R_RESOURCES_DIR_WIN) | ||||
|  | @ -32,6 +33,8 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1) | |||
| option(SLIC3R_MSVC_PDB          "Generate PDB files on MSVC in Release mode" 1) | ||||
| option(SLIC3R_PERL_XS           "Compile XS Perl module and enable Perl unit and integration tests" 0) | ||||
| option(SLIC3R_ASAN              "Enable ASan on Clang and GCC" 0) | ||||
| # If SLIC3R_FHS is 1 -> SLIC3R_DESKTOP_INTEGRATION is always 0, othrewise variable. | ||||
| CMAKE_DEPENDENT_OPTION(SLIC3R_DESKTOP_INTEGRATION "Allow perfoming desktop integration during runtime" 0 "NOT SLIC3R_FHS" 0) | ||||
| 
 | ||||
| set(OPENVDB_FIND_MODULE_PATH "" CACHE PATH "Path to OpenVDB installation's find modules.") | ||||
| 
 | ||||
|  | @ -71,6 +74,10 @@ if (SLIC3R_GUI) | |||
|     add_definitions(-DSLIC3R_GUI) | ||||
| endif () | ||||
| 
 | ||||
| if(SLIC3R_DESKTOP_INTEGRATION) | ||||
|     add_definitions(-DSLIC3R_DESKTOP_INTEGRATION) | ||||
| endif () | ||||
| 
 | ||||
| if (MSVC AND CMAKE_CXX_COMPILER_ID STREQUAL Clang) | ||||
|     set(IS_CLANG_CL TRUE) | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,15 +1,18 @@ | |||
| #ifdef __linux__ | ||||
| #include "DesktopIntegrationDialog.hpp" | ||||
| #include "GUI_App.hpp" | ||||
| #include "GUI.hpp" | ||||
| #include "format.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "NotificationManager.hpp" | ||||
| #include "libslic3r/AppConfig.hpp" | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "libslic3r/Platform.hpp" | ||||
| #include "libslic3r/Config.hpp" | ||||
| 
 | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/log/trivial.hpp> | ||||
| #include <boost/dll/runtime_symbol_info.hpp> | ||||
| 
 | ||||
| #include <wx/filename.h> | ||||
| #include <wx/stattext.h> | ||||
|  | @ -17,9 +20,9 @@ | |||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
| 
 | ||||
| namespace integrate_desktop_internal{ | ||||
| namespace { | ||||
| // Disects path strings stored in system variable divided by ':' and adds into vector
 | ||||
| static void resolve_path_from_var(const std::string& var, std::vector<std::string>& paths) | ||||
| void resolve_path_from_var(const std::string& var, std::vector<std::string>& paths) | ||||
| { | ||||
|     wxString wxdirs; | ||||
|     if (! wxGetEnv(boost::nowide::widen(var), &wxdirs) || wxdirs.empty() ) | ||||
|  | @ -34,7 +37,7 @@ static void resolve_path_from_var(const std::string& var, std::vector<std::strin | |||
|     paths.push_back(dirs); | ||||
| } | ||||
| // Return true if directory in path p+dir_name exists
 | ||||
| static bool contains_path_dir(const std::string& p, const std::string& dir_name) | ||||
| bool contains_path_dir(const std::string& p, const std::string& dir_name) | ||||
| { | ||||
|     if (p.empty() || dir_name.empty())  | ||||
|        return false; | ||||
|  | @ -47,7 +50,7 @@ static bool contains_path_dir(const std::string& p, const std::string& dir_name) | |||
|     return false; | ||||
| } | ||||
| // Creates directory in path if not exists yet
 | ||||
| static void create_dir(const boost::filesystem::path& path) | ||||
| void create_dir(const boost::filesystem::path& path) | ||||
| { | ||||
|     if (boost::filesystem::exists(path)) | ||||
|         return; | ||||
|  | @ -58,7 +61,7 @@ static void create_dir(const boost::filesystem::path& path) | |||
|         BOOST_LOG_TRIVIAL(error)<< "create directory failed: " << ec.message(); | ||||
| } | ||||
| // Starts at basic_path (excluded) and creates all directories in dir_path
 | ||||
| static void create_path(const std::string& basic_path, const std::string& dir_path) | ||||
| void create_path(const std::string& basic_path, const std::string& dir_path) | ||||
| { | ||||
|     if (basic_path.empty() || dir_path.empty()) | ||||
|        return; | ||||
|  | @ -76,7 +79,7 @@ static void create_path(const std::string& basic_path, const std::string& dir_pa | |||
|     create_dir(path); | ||||
| } | ||||
| // Calls our internal copy_file function to copy file at icon_path to dest_path
 | ||||
| static bool copy_icon(const std::string& icon_path, const std::string& dest_path) | ||||
| bool copy_icon(const std::string& icon_path, const std::string& dest_path) | ||||
| { | ||||
|     BOOST_LOG_TRIVIAL(debug) <<"icon from "<< icon_path; | ||||
|     BOOST_LOG_TRIVIAL(debug) <<"icon to "<< dest_path; | ||||
|  | @ -90,8 +93,8 @@ static bool copy_icon(const std::string& icon_path, const std::string& dest_path | |||
|     return true; | ||||
| } | ||||
| // Creates new file filled with data.
 | ||||
| static bool create_desktop_file(const std::string& path, const std::string& data) | ||||
| { | ||||
| bool create_desktop_file(const std::string& path, const std::string& data) | ||||
| {     | ||||
|     BOOST_LOG_TRIVIAL(debug) <<".desktop to "<< path; | ||||
|     std::ofstream output(path); | ||||
|     output << data; | ||||
|  | @ -109,10 +112,6 @@ static 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.
 | ||||
| bool DesktopIntegrationDialog::is_integrated() | ||||
| { | ||||
| 	const char *appimage_env = std::getenv("APPIMAGE"); | ||||
|     if (!appimage_env)  | ||||
|         return false; | ||||
|   | ||||
|     const AppConfig *app_config = wxGetApp().app_config; | ||||
|     std::string path(app_config->get("desktop_integration_app_path")); | ||||
|     BOOST_LOG_TRIVIAL(debug) << "Desktop integration desktop file path: " << path; | ||||
|  | @ -126,10 +125,6 @@ bool DesktopIntegrationDialog::is_integrated() | |||
| } | ||||
| bool DesktopIntegrationDialog::integration_possible() | ||||
| { | ||||
| 
 | ||||
| 	const char *appimage_env = std::getenv("APPIMAGE"); | ||||
|     if (!appimage_env) | ||||
|         return false; | ||||
|     return true; | ||||
| } | ||||
| void DesktopIntegrationDialog::perform_desktop_integration() | ||||
|  | @ -143,14 +138,26 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|         try { | ||||
|             appimage_path = boost::filesystem::canonical(boost::filesystem::path(appimage_env)).string(); | ||||
|         } catch (std::exception &) {             | ||||
|             BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - boost::filesystem::canonical did not return appimage path."; | ||||
|             show_error(nullptr, _L("Performing desktop integration failed - boost::filesystem::canonical did not return appimage path.")); | ||||
|             return; | ||||
|         } | ||||
|     } else { | ||||
|         // not appimage - not performing
 | ||||
|         BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - not Appimage executable."; | ||||
|         wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); | ||||
|         return; | ||||
|         // not appimage - find executable
 | ||||
|         appimage_path = boost::dll::program_location().string(); | ||||
|         //appimage_path = wxStandardPaths::Get().GetExecutablePath().string();
 | ||||
|         BOOST_LOG_TRIVIAL(debug) << "non-appimage path to executable: " << appimage_path; | ||||
|         if (appimage_path.empty()) | ||||
|         { | ||||
|             BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - no executable found."; | ||||
|             show_error(nullptr, _L("Performing desktop integration failed - Could not find executable.")); | ||||
|             return;  | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Escape ' characters in appimage, other special symbols will be esacaped in desktop file by 'appimage_path'
 | ||||
|     //appimage_path = std::regex_replace(appimage_path, std::regex("\'"), "\\\'");
 | ||||
| 
 | ||||
|     // Find directories icons and applications
 | ||||
|     // $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. 
 | ||||
|  | @ -158,8 +165,8 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|     // 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::vector<std::string>target_candidates; | ||||
|     integrate_desktop_internal::resolve_path_from_var("XDG_DATA_HOME", target_candidates); | ||||
|     integrate_desktop_internal::resolve_path_from_var("XDG_DATA_DIRS", target_candidates); | ||||
|     resolve_path_from_var("XDG_DATA_HOME", target_candidates); | ||||
|     resolve_path_from_var("XDG_DATA_DIRS", target_candidates); | ||||
| 
 | ||||
|     AppConfig *app_config = wxGetApp().app_config; | ||||
|     // suffix string to create different desktop file for alpha, beta.
 | ||||
|  | @ -186,7 +193,6 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|         icon_theme_dirs = "/hicolor/96x96/apps"; | ||||
|     } | ||||
|      | ||||
|      | ||||
|     std::string target_dir_icons; | ||||
|     std::string target_dir_desktop; | ||||
|      | ||||
|  | @ -194,24 +200,24 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|     // iterate thru target_candidates to find icons folder
 | ||||
|     for (size_t i = 0; i < target_candidates.size(); ++i) { | ||||
|         // Copy icon PrusaSlicer.png from resources_dir()/icons to target_dir_icons/icons/
 | ||||
|         if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "icons")) { | ||||
|         if (contains_path_dir(target_candidates[i], "icons")) { | ||||
|             target_dir_icons = target_candidates[i]; | ||||
|             std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); | ||||
|             std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); | ||||
|             if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) | ||||
|             if (copy_icon(icon_path, dest_path)) | ||||
|                 break; // success
 | ||||
|             else | ||||
|                 target_dir_icons.clear(); // copying failed
 | ||||
|             // if all failed - try creating default home folder
 | ||||
|             if (i == target_candidates.size() - 1) { | ||||
|                 // create $HOME/.local/share
 | ||||
|                 integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); | ||||
|                 create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/icons" + icon_theme_dirs); | ||||
|                 // copy icon
 | ||||
|                 target_dir_icons = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); | ||||
|                 std::string icon_path = GUI::format("%1%/icons/PrusaSlicer.png",resources_dir()); | ||||
|                 std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer%3%.png", target_dir_icons, icon_theme_path, version_suffix); | ||||
|                 if (!integrate_desktop_internal::contains_path_dir(target_dir_icons, "icons")  | ||||
|                     || !integrate_desktop_internal::copy_icon(icon_path, dest_path)) { | ||||
|                 if (!contains_path_dir(target_dir_icons, "icons")  | ||||
|                     || !copy_icon(icon_path, dest_path)) { | ||||
|                 	// every attempt failed - icon wont be present
 | ||||
|                     target_dir_icons.clear();  | ||||
|                 } | ||||
|  | @ -228,7 +234,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|     // iterate thru target_candidates to find applications folder
 | ||||
|     for (size_t i = 0; i < target_candidates.size(); ++i) | ||||
|     { | ||||
|         if (integrate_desktop_internal::contains_path_dir(target_candidates[i], "applications")) { | ||||
|         if (contains_path_dir(target_candidates[i], "applications")) { | ||||
|             target_dir_desktop = target_candidates[i]; | ||||
|             // Write slicer desktop file
 | ||||
|             std::string desktop_file = GUI::format( | ||||
|  | @ -236,7 +242,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|                 "Name=PrusaSlicer%1%\n" | ||||
|                 "GenericName=3D Printing Software\n" | ||||
|                 "Icon=PrusaSlicer%2%\n" | ||||
|                 "Exec=%3% %%F\n" | ||||
|                 "Exec=\'%3%\' %%F\n" | ||||
|                 "Terminal=false\n" | ||||
|                 "Type=Application\n" | ||||
|                 "MimeType=model/stl;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;\n" | ||||
|  | @ -246,23 +252,23 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|                 "StartupWMClass=prusa-slicer", name_suffix, version_suffix, appimage_path); | ||||
| 
 | ||||
|             std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); | ||||
|             if (integrate_desktop_internal::create_desktop_file(path, desktop_file)){ | ||||
|             if (create_desktop_file(path, desktop_file)){ | ||||
|                 BOOST_LOG_TRIVIAL(debug) << "PrusaSlicer.desktop file installation success."; | ||||
|                 break; | ||||
|             } else { | ||||
|             	// write failed - try another path
 | ||||
|                 BOOST_LOG_TRIVIAL(error) << "PrusaSlicer.desktop file installation failed."; | ||||
|                 BOOST_LOG_TRIVIAL(debug) << "Attempt to PrusaSlicer.desktop file installation failed. failed path: " << target_candidates[i]; | ||||
|                 target_dir_desktop.clear();  | ||||
|             } | ||||
|             // if all failed - try creating default home folder
 | ||||
|             if (i == target_candidates.size() - 1) { | ||||
|                 // create $HOME/.local/share
 | ||||
|                 integrate_desktop_internal::create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); | ||||
|                 create_path(boost::nowide::narrow(wxFileName::GetHomeDir()), ".local/share/applications"); | ||||
|                 // create desktop file
 | ||||
|                 target_dir_desktop = GUI::format("%1%/.local/share",wxFileName::GetHomeDir()); | ||||
|                 std::string path = GUI::format("%1%/applications/PrusaSlicer%2%.desktop", target_dir_desktop, version_suffix); | ||||
|                 if (integrate_desktop_internal::contains_path_dir(target_dir_desktop, "applications")) { | ||||
|                     if (!integrate_desktop_internal::create_desktop_file(path, desktop_file)) {     | ||||
|                 if (contains_path_dir(target_dir_desktop, "applications")) { | ||||
|                     if (!create_desktop_file(path, desktop_file)) {     | ||||
|                         // Desktop file not written - end desktop integration
 | ||||
|                         BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create desktop file"; | ||||
|                         return; | ||||
|  | @ -278,7 +284,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|     if(target_dir_desktop.empty()) { | ||||
|     	// Desktop file not written - end desktop integration
 | ||||
|         BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not find applications directory"; | ||||
|         wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); | ||||
|         show_error(nullptr, _L("Performing desktop integration failed - could not find applications directory.")); | ||||
|         return; | ||||
|     } | ||||
|     // save path to desktop file
 | ||||
|  | @ -290,7 +296,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|     { | ||||
|     	std::string icon_path = GUI::format("%1%/icons/PrusaSlicer-gcodeviewer_192px.png",resources_dir()); | ||||
| 	    std::string dest_path = GUI::format("%1%/icons/%2%PrusaSlicer-gcodeviewer%3%.png", target_dir_icons, icon_theme_path, version_suffix); | ||||
| 	    if (integrate_desktop_internal::copy_icon(icon_path, dest_path)) | ||||
| 	    if (copy_icon(icon_path, dest_path)) | ||||
| 	    	// save path to icon
 | ||||
| 	        app_config->set("desktop_integration_icon_viewer_path", dest_path); | ||||
| 	    else | ||||
|  | @ -303,7 +309,7 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|         "Name=Prusa Gcode Viewer%1%\n" | ||||
|         "GenericName=3D Printing Software\n" | ||||
|         "Icon=PrusaSlicer-gcodeviewer%2%\n" | ||||
|         "Exec=%3% --gcodeviwer %%F\n" | ||||
|         "Exec=\'%3%\' --gcodeviwer %%F\n" | ||||
|         "Terminal=false\n" | ||||
|         "Type=Application\n" | ||||
|         "MimeType=text/x.gcode;\n" | ||||
|  | @ -312,23 +318,17 @@ void DesktopIntegrationDialog::perform_desktop_integration() | |||
|         "StartupNotify=false", name_suffix, version_suffix, appimage_path); | ||||
| 
 | ||||
|     std::string desktop_path = GUI::format("%1%/applications/PrusaSlicerGcodeViewer%2%.desktop", target_dir_desktop, version_suffix); | ||||
|     if (integrate_desktop_internal::create_desktop_file(desktop_path, desktop_file)) | ||||
|     if (create_desktop_file(desktop_path, desktop_file)) | ||||
|     	// save path to desktop file
 | ||||
|         app_config->set("desktop_integration_app_viewer_path", desktop_path); | ||||
|     else { | ||||
|         BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could create gcode viewer desktop file"; | ||||
|          wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationFail); | ||||
|         BOOST_LOG_TRIVIAL(error) << "Performing desktop integration failed - could not create Gcodeviewer desktop file"; | ||||
|         show_error(nullptr, _L("Performing desktop integration failed - could not create Gcodeviewer desktop file. PrusaSlicer desktop file was probably created successfully.")); | ||||
|     } | ||||
|     wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::DesktopIntegrationSuccess); | ||||
| } | ||||
| void DesktopIntegrationDialog::undo_desktop_intgration() | ||||
| { | ||||
| 	const char *appimage_env = std::getenv("APPIMAGE"); | ||||
|     if (!appimage_env) { | ||||
|         BOOST_LOG_TRIVIAL(error) << "Undo desktop integration failed - not Appimage executable."; | ||||
|     	wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::UndoDesktopIntegrationFail); | ||||
|         return; | ||||
|     } | ||||
|     const AppConfig *app_config = wxGetApp().app_config; | ||||
|     // slicer .desktop
 | ||||
|     std::string path = std::string(app_config->get("desktop_integration_app_path")); | ||||
|  |  | |||
|  | @ -1806,10 +1806,10 @@ void GUI_App::add_config_menu(wxMenuBar *menu) | |||
|         local_menu->Append(config_id_base + ConfigMenuSnapshots, _L("&Configuration Snapshots") + dots, _L("Inspect / activate configuration snapshots")); | ||||
|         local_menu->Append(config_id_base + ConfigMenuTakeSnapshot, _L("Take Configuration &Snapshot"), _L("Capture a configuration snapshot")); | ||||
|         local_menu->Append(config_id_base + ConfigMenuUpdate, _L("Check for updates"), _L("Check for configuration updates")); | ||||
| #ifdef __linux__ | ||||
|         if (DesktopIntegrationDialog::integration_possible()) | ||||
|             local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration"));     | ||||
| #endif         | ||||
| #if defined(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)  | ||||
|         //if (DesktopIntegrationDialog::integration_possible())
 | ||||
|         local_menu->Append(config_id_base + ConfigMenuDesktopIntegration, _L("Desktop Integration"), _L("Desktop Integration"));     | ||||
| #endif //(__linux__) && defined(SLIC3R_DESKTOP_INTEGRATION)        
 | ||||
|         local_menu->AppendSeparator(); | ||||
|     } | ||||
|     local_menu->Append(config_id_base + ConfigMenuPreferences, _L("&Preferences") + dots + | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David Kocik
						David Kocik