Worked around some quirky Linux file system issues. Namely
the Chromebooks share their file system to Linux using the 9p file system, which does not support setting file ownership. Newly PrusaSlicer will detect platform and it will not panick if copy_file() cannot set file ownership after copying. It just logs the incident, and on chromebooks the loglevel for that incident is "Info", not "Error". Adjusted the full screen mode to contain menu bar. Moved Platform.cpp/hpp to libslic3r
This commit is contained in:
parent
84a333e4ed
commit
01406fd521
@ -38,6 +38,7 @@
|
||||
#include "libslic3r/GCode/PostProcessor.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/ModelArrange.hpp"
|
||||
#include "libslic3r/Platform.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include "libslic3r/TriangleMesh.hpp"
|
||||
@ -68,6 +69,8 @@ int CLI::run(int argc, char **argv)
|
||||
{
|
||||
// Mark the main thread for the debugger and for runtime checks.
|
||||
set_current_thread_name("slic3r_main");
|
||||
// Detect the operating system flavor.
|
||||
detect_platform();
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// On Linux, wxGTK has no support for Wayland, and the app crashes on
|
||||
|
@ -141,6 +141,8 @@ add_library(libslic3r STATIC
|
||||
PerimeterGenerator.hpp
|
||||
PlaceholderParser.cpp
|
||||
PlaceholderParser.hpp
|
||||
Platform.cpp
|
||||
Platform.hpp
|
||||
Point.cpp
|
||||
Point.hpp
|
||||
Polygon.cpp
|
||||
|
@ -1,15 +1,8 @@
|
||||
#include "Platform.hpp"
|
||||
|
||||
|
||||
// For starting another PrusaSlicer instance on OSX.
|
||||
// Fails to compile on Windows on the build server.
|
||||
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
static auto s_platform = Platform::Uninitialized;
|
||||
static auto s_platform_flavor = PlatformFlavor::Uninitialized;
|
||||
@ -74,5 +67,4 @@ PlatformFlavor platform_flavor()
|
||||
return s_platform_flavor;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
@ -1,8 +1,7 @@
|
||||
#ifndef SLIC3R_GUI_Utils_Platform_HPP
|
||||
#define SLIC3R_GUI_Utils_Platform_HPP
|
||||
#ifndef SLIC3R_Platform_HPP
|
||||
#define SLIC3R_Platform_HPP
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
enum class Platform
|
||||
{
|
||||
@ -37,8 +36,6 @@ void detect_platform();
|
||||
Platform platform();
|
||||
PlatformFlavor platform_flavor();
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // SLIC3R_GUI_Utils_Platform_HPP
|
||||
#endif // SLIC3R_Platform_HPP
|
@ -6,6 +6,7 @@
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Platform.hpp"
|
||||
#include "Time.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
@ -22,6 +23,11 @@
|
||||
#ifdef __APPLE__
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/sendfile.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/log/core.hpp>
|
||||
@ -417,6 +423,140 @@ std::error_code rename_file(const std::string &from, const std::string &to)
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
// Copied from boost::filesystem, to support copying a file to a weird filesystem, which does not support changing file attributes,
|
||||
// for example ChromeOS Linux integration or FlashAIR WebDAV.
|
||||
// Copied and simplified from boost::filesystem::detail::copy_file() with option = overwrite_if_exists and with just the Linux path kept,
|
||||
// and only features supported by Linux 3.10 (on our build server with CentOS 7) are kept, namely sendfile with ranges and statx() are not supported.
|
||||
bool copy_file_linux(const boost::filesystem::path &from, const boost::filesystem::path &to, boost::system::error_code &ec)
|
||||
{
|
||||
using namespace boost::filesystem;
|
||||
|
||||
struct fd_wrapper
|
||||
{
|
||||
int fd { -1 };
|
||||
fd_wrapper() = default;
|
||||
explicit fd_wrapper(int fd) throw() : fd(fd) {}
|
||||
~fd_wrapper() throw() { if (fd >= 0) ::close(fd); }
|
||||
};
|
||||
|
||||
ec.clear();
|
||||
int err = 0;
|
||||
|
||||
// Note: Declare fd_wrappers here so that errno is not clobbered by close() that may be called in fd_wrapper destructors
|
||||
fd_wrapper infile, outfile;
|
||||
|
||||
while (true) {
|
||||
infile.fd = ::open(from.c_str(), O_RDONLY | O_CLOEXEC);
|
||||
if (infile.fd < 0) {
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
fail:
|
||||
ec.assign(err, boost::system::system_category());
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
struct ::stat from_stat;
|
||||
if (::fstat(infile.fd, &from_stat) != 0) {
|
||||
fail_errno:
|
||||
err = errno;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
const mode_t from_mode = from_stat.st_mode;
|
||||
if (!S_ISREG(from_mode)) {
|
||||
err = ENOSYS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Enable writing for the newly created files. Having write permission set is important e.g. for NFS,
|
||||
// which checks the file permission on the server, even if the client's file descriptor supports writing.
|
||||
mode_t to_mode = from_mode | S_IWUSR;
|
||||
int oflag = O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC;
|
||||
|
||||
while (true) {
|
||||
outfile.fd = ::open(to.c_str(), oflag, to_mode);
|
||||
if (outfile.fd < 0) {
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
struct ::stat to_stat;
|
||||
if (::fstat(outfile.fd, &to_stat) != 0)
|
||||
goto fail_errno;
|
||||
|
||||
to_mode = to_stat.st_mode;
|
||||
if (!S_ISREG(to_mode)) {
|
||||
err = ENOSYS;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (from_stat.st_dev == to_stat.st_dev && from_stat.st_ino == to_stat.st_ino) {
|
||||
err = EEXIST;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
//! copy_file implementation that uses sendfile loop. Requires sendfile to support file descriptors.
|
||||
//FIXME Vojtech: This is a copy loop valid for Linux 2.6.33 and newer.
|
||||
// copy_file_data_copy_file_range() supports cross-filesystem copying since 5.3, but Vojtech did not want to polute this
|
||||
// function with that, we don't think the performance gain is worth it for the types of files we are copying,
|
||||
// and our build server based on CentOS 7 with Linux 3.10 does not support that anyways.
|
||||
{
|
||||
// sendfile will not send more than this amount of data in one call
|
||||
constexpr std::size_t max_send_size = 0x7ffff000u;
|
||||
uintmax_t offset = 0u;
|
||||
while (off_t(offset) < from_stat.st_size) {
|
||||
uintmax_t size_left = from_stat.st_size - offset;
|
||||
std::size_t size_to_copy = max_send_size;
|
||||
if (size_left < static_cast<uintmax_t>(max_send_size))
|
||||
size_to_copy = static_cast<std::size_t>(size_left);
|
||||
ssize_t sz = ::sendfile(outfile.fd, infile.fd, nullptr, size_to_copy);
|
||||
if (sz < 0) {
|
||||
err = errno;
|
||||
if (err == EINTR)
|
||||
continue;
|
||||
if (err == 0)
|
||||
break;
|
||||
goto fail; // err already contains the error code
|
||||
}
|
||||
offset += sz;
|
||||
}
|
||||
}
|
||||
|
||||
// If we created a new file with an explicitly added S_IWUSR permission,
|
||||
// we may need to update its mode bits to match the source file.
|
||||
if (to_mode != from_mode && ::fchmod(outfile.fd, from_mode) != 0) {
|
||||
if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
|
||||
// Ignore that. 9p filesystem does not allow fmod().
|
||||
BOOST_LOG_TRIVIAL(info) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message() <<
|
||||
" This may be expected when writing to a 9p filesystem.";
|
||||
} else {
|
||||
// Generic linux. Write out an error to console. At least we may get some feedback.
|
||||
BOOST_LOG_TRIVIAL(error) << "copy_file_linux() failed to fchmod() the output file \"" << to.string() << "\" to " << from_mode << ": " << ec.message();
|
||||
}
|
||||
}
|
||||
|
||||
// Note: Use fsync/fdatasync followed by close to avoid dealing with the possibility of close failing with EINTR.
|
||||
// Even if close fails, including with EINTR, most operating systems (presumably, except HP-UX) will close the
|
||||
// file descriptor upon its return. This means that if an error happens later, when the OS flushes data to the
|
||||
// underlying media, this error will go unnoticed and we have no way to receive it from close. Calling fsync/fdatasync
|
||||
// ensures that all data have been written, and even if close fails for some unfathomable reason, we don't really
|
||||
// care at that point.
|
||||
err = ::fdatasync(outfile.fd);
|
||||
if (err != 0)
|
||||
goto fail_errno;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // __linux__
|
||||
|
||||
CopyFileResult copy_file_inner(const std::string& from, const std::string& to, std::string& error_message)
|
||||
{
|
||||
const boost::filesystem::path source(from);
|
||||
@ -434,7 +574,13 @@ CopyFileResult copy_file_inner(const std::string& from, const std::string& to, s
|
||||
if (ec)
|
||||
BOOST_LOG_TRIVIAL(debug) << "boost::filesystem::permisions before copy error message (this could be irrelevant message based on file system): " << ec.message();
|
||||
ec.clear();
|
||||
#ifdef __linux__
|
||||
// We want to allow copying files on Linux to succeed even if changing the file attributes fails.
|
||||
// That may happen when copying on some exotic file system, for example Linux on Chrome.
|
||||
copy_file_linux(source, target, ec);
|
||||
#else // __linux__
|
||||
boost::filesystem::copy_file(source, target, boost::filesystem::copy_option::overwrite_if_exists, ec);
|
||||
#endif // __linux__
|
||||
if (ec) {
|
||||
error_message = ec.message();
|
||||
return FAIL_COPY_FILE;
|
||||
|
@ -209,8 +209,6 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/Bonjour.hpp
|
||||
Utils/PresetUpdater.cpp
|
||||
Utils/PresetUpdater.hpp
|
||||
Utils/Platform.cpp
|
||||
Utils/Platform.hpp
|
||||
Utils/Process.cpp
|
||||
Utils/Process.hpp
|
||||
Utils/Profile.hpp
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/MainFrame.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
|
||||
// To show a message box if GUI initialization ends up with an exception thrown.
|
||||
#include <wx/msgdlg.h>
|
||||
@ -37,8 +36,6 @@ int GUI_Run(GUI_InitParams ¶ms)
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
#endif // __APPLE__
|
||||
|
||||
detect_platform();
|
||||
|
||||
try {
|
||||
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
|
||||
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
|
||||
|
@ -1218,8 +1218,10 @@ void MainFrame::init_menubar_as_editor()
|
||||
[this](wxCommandEvent&) { m_plater->collapse_sidebar(!m_plater->is_sidebar_collapsed()); }, this,
|
||||
[]() { return true; }, [this]() { return m_plater->is_sidebar_collapsed(); }, this);
|
||||
append_menu_check_item(viewMenu, wxID_ANY, _L("&Full screen") + "\t" + "F11", _L("Full screen"),
|
||||
[this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen()); }, this,
|
||||
[]() { return true; }, [this]() { return this->IsFullScreen(); }, this);
|
||||
[this](wxCommandEvent&) { this->ShowFullScreen(!this->IsFullScreen(),
|
||||
// wxFULLSCREEN_ALL: wxFULLSCREEN_NOMENUBAR | wxFULLSCREEN_NOTOOLBAR | wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION
|
||||
wxFULLSCREEN_NOSTATUSBAR | wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION); },
|
||||
this, []() { return true; }, [this]() { return this->IsFullScreen(); }, this);
|
||||
}
|
||||
|
||||
// Help menu
|
||||
|
@ -4,7 +4,8 @@
|
||||
#include "GUI.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
|
||||
#include "libslic3r/Platform.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
@ -324,7 +325,7 @@ void OpenGLManager::detect_multisample(int* attribList)
|
||||
enable_multisample &&
|
||||
// Disable multi-sampling on ChromeOS, as the OpenGL virtualization swaps Red/Blue channels with multi-sampling enabled,
|
||||
// at least on some platforms.
|
||||
(platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
|
||||
platform_flavor() != PlatformFlavor::LinuxOnChromium &&
|
||||
wxGLCanvas::IsDisplaySupported(attribList)
|
||||
? EMultisampleState::Enabled : EMultisampleState::Disabled;
|
||||
// Alternative method: it was working on previous version of wxWidgets but not with the latest, at least on Windows
|
||||
|
@ -76,7 +76,6 @@
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/Platform.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "InstanceCheck.hpp"
|
||||
@ -89,7 +88,9 @@
|
||||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include "libslic3r/CustomGCode.hpp"
|
||||
#include "libslic3r/Platform.hpp"
|
||||
|
||||
using boost::optional;
|
||||
namespace fs = boost::filesystem;
|
||||
@ -3660,7 +3661,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path,
|
||||
// Don't offer the "Eject" button on ChromeOS, the Linux side has no control over it.
|
||||
platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium);
|
||||
platform_flavor() != PlatformFlavor::LinuxOnChromium);
|
||||
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
|
||||
|
@ -139,7 +139,6 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle
|
||||
const ConfigOptionFloatOrPercent *first_layer_extrusion_width_ptr = (first_layer && first_layer_extrusion_width.value > 0) ?
|
||||
&first_layer_extrusion_width : nullptr;
|
||||
const float lh = float(first_layer ? first_layer_height : layer_height);
|
||||
const float bfr = bridging ? bridge_flow_ratio : 0.f;
|
||||
double max_flow = 0.;
|
||||
std::string max_flow_extrusion_type;
|
||||
auto limit_by_first_layer_speed = [&first_layer_speed, first_layer](double speed_normal, double speed_max) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "slic3r/Utils/Platform.hpp"
|
||||
#include "libslic3r/Platform.hpp"
|
||||
#include <libslic3r/libslic3r.h>
|
||||
|
||||
#include <boost/nowide/convert.hpp>
|
||||
@ -232,7 +232,7 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
|
||||
|
||||
#else
|
||||
|
||||
if (platform() == Platform::Linux && platform_flavor() == PlatformFlavor::LinuxOnChromium) {
|
||||
if (platform_flavor() == PlatformFlavor::LinuxOnChromium) {
|
||||
// ChromeOS specific: search /mnt/chromeos/removable/* folder
|
||||
search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
|
||||
} else {
|
||||
@ -452,7 +452,7 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
|
||||
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
||||
out.has_eject =
|
||||
// Cannot control eject on Chromium.
|
||||
(platform() != Platform::Linux || platform_flavor() != PlatformFlavor::LinuxOnChromium) &&
|
||||
platform_flavor() != PlatformFlavor::LinuxOnChromium &&
|
||||
this->find_last_save_path_drive_data() != m_current_drives.end();
|
||||
out.has_removable_drives = ! m_current_drives.empty();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user