Ported ChromeOS support from master aka PrusaSlicer 2.4.0-alpha:
1) Detect platform 2) Disable OpenGL multi-sampling on ChromeOS 3) Disable eject on ChromeOS, different location of external devices mount point.
This commit is contained in:
parent
89b942ffb7
commit
db324b2295
@ -37,6 +37,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"
|
||||
@ -594,6 +595,9 @@ bool CLI::setup(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect the operating system flavor after SLIC3R_LOGLEVEL is set.
|
||||
detect_platform();
|
||||
|
||||
boost::filesystem::path path_to_binary = boost::filesystem::system_complete(argv[0]);
|
||||
|
||||
// Path from the Slic3r binary to its resources.
|
||||
|
@ -137,6 +137,8 @@ add_library(libslic3r STATIC
|
||||
PerimeterGenerator.hpp
|
||||
PlaceholderParser.cpp
|
||||
PlaceholderParser.hpp
|
||||
Platform.cpp
|
||||
Platform.hpp
|
||||
Point.cpp
|
||||
Point.hpp
|
||||
Polygon.cpp
|
||||
|
71
src/libslic3r/Platform.cpp
Normal file
71
src/libslic3r/Platform.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "Platform.hpp"
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static auto s_platform = Platform::Uninitialized;
|
||||
static auto s_platform_flavor = PlatformFlavor::Uninitialized;
|
||||
|
||||
void detect_platform()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform: Windows";
|
||||
s_platform = Platform::Windows;
|
||||
s_platform_flavor = PlatformFlavor::Generic;
|
||||
#elif defined(__APPLE__)
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform: OSX";
|
||||
s_platform = Platform::OSX;
|
||||
s_platform_flavor = PlatformFlavor::Generic;
|
||||
#elif defined(__linux__)
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform: Linux";
|
||||
s_platform = Platform::Linux;
|
||||
s_platform_flavor = PlatformFlavor::GenericLinux;
|
||||
// Test for Chromium.
|
||||
{
|
||||
FILE *f = ::fopen("/proc/version", "rt");
|
||||
if (f) {
|
||||
char buf[4096];
|
||||
// Read the 1st line.
|
||||
if (::fgets(buf, 4096, f)) {
|
||||
if (strstr(buf, "Chromium OS") != nullptr) {
|
||||
s_platform_flavor = PlatformFlavor::LinuxOnChromium;
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform flavor: LinuxOnChromium";
|
||||
} else if (strstr(buf, "microsoft") != nullptr || strstr(buf, "Microsoft") != nullptr) {
|
||||
if (boost::filesystem::exists("/run/WSL") && getenv("WSL_INTEROP") != nullptr) {
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL2";
|
||||
s_platform_flavor = PlatformFlavor::WSL2;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform flavor: WSL";
|
||||
s_platform_flavor = PlatformFlavor::WSL;
|
||||
}
|
||||
}
|
||||
}
|
||||
::fclose(f);
|
||||
}
|
||||
}
|
||||
#elif defined(__OpenBSD__)
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform: OpenBSD";
|
||||
s_platform = Platform::BSDUnix;
|
||||
s_platform_flavor = PlatformFlavor::OpenBSD;
|
||||
#else
|
||||
// This should not happen.
|
||||
BOOST_LOG_TRIVIAL(info) << "Platform: Unknown";
|
||||
static_assert(false, "Unknown platform detected");
|
||||
s_platform = Platform::Unknown;
|
||||
s_platform_flavor = PlatformFlavor::Unknown;
|
||||
#endif
|
||||
}
|
||||
|
||||
Platform platform()
|
||||
{
|
||||
return s_platform;
|
||||
}
|
||||
|
||||
PlatformFlavor platform_flavor()
|
||||
{
|
||||
return s_platform_flavor;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
41
src/libslic3r/Platform.hpp
Normal file
41
src/libslic3r/Platform.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef SLIC3R_Platform_HPP
|
||||
#define SLIC3R_Platform_HPP
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class Platform
|
||||
{
|
||||
Uninitialized,
|
||||
Unknown,
|
||||
Windows,
|
||||
OSX,
|
||||
Linux,
|
||||
BSDUnix,
|
||||
};
|
||||
|
||||
enum class PlatformFlavor
|
||||
{
|
||||
Uninitialized,
|
||||
Unknown,
|
||||
// For Windows and OSX, until we need to be more specific.
|
||||
Generic,
|
||||
// For Platform::Linux
|
||||
GenericLinux,
|
||||
LinuxOnChromium,
|
||||
// Microsoft's Windows on Linux (Linux kernel simulated on NTFS kernel)
|
||||
WSL,
|
||||
// Microsoft's Windows on Linux, version 2 (virtual machine)
|
||||
WSL2,
|
||||
// For Platform::BSDUnix
|
||||
OpenBSD,
|
||||
};
|
||||
|
||||
// To be called on program start-up.
|
||||
void detect_platform();
|
||||
|
||||
Platform platform();
|
||||
PlatformFlavor platform_flavor();
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // SLIC3R_Platform_HPP
|
@ -6,6 +6,7 @@
|
||||
#include <cstdarg>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "Platform.hpp"
|
||||
#include "Time.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
@ -417,6 +418,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 +569,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;
|
||||
|
@ -5,6 +5,8 @@
|
||||
#include "I18N.hpp"
|
||||
#include "3DScene.hpp"
|
||||
|
||||
#include "libslic3r/Platform.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
@ -333,7 +335,13 @@ void OpenGLManager::detect_multisample(int* attribList)
|
||||
{
|
||||
int wxVersion = wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + wxRELEASE_NUMBER;
|
||||
bool enable_multisample = wxVersion >= 30003;
|
||||
s_multisample = (enable_multisample && wxGLCanvas::IsDisplaySupported(attribList)) ? EMultisampleState::Enabled : EMultisampleState::Disabled;
|
||||
s_multisample =
|
||||
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_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
|
||||
// s_multisample = enable_multisample && wxGLCanvas::IsExtensionSupported("WGL_ARB_multisample");
|
||||
}
|
||||
|
@ -88,6 +88,7 @@
|
||||
#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;
|
||||
@ -3769,7 +3770,9 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
// If writing to removable drive was scheduled, show notification with eject button
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
|
||||
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_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);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "libslic3r/Platform.hpp"
|
||||
#include <libslic3r/libslic3r.h>
|
||||
|
||||
#include <boost/nowide/convert.hpp>
|
||||
@ -185,8 +186,13 @@ namespace search_for_drives_internal
|
||||
{
|
||||
//confirms if the file is removable drive and adds it to vector
|
||||
|
||||
//if not same file system - could be removable drive
|
||||
if (! compare_filesystem_id(path, parent_path)) {
|
||||
if (
|
||||
#ifdef __linux__
|
||||
// Chromium mounts removable drives in a way that produces the same device ID.
|
||||
platform_flavor() == PlatformFlavor::LinuxOnChromium ||
|
||||
#endif
|
||||
// If not same file system - could be removable drive.
|
||||
! compare_filesystem_id(path, parent_path)) {
|
||||
//free space
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path, ec);
|
||||
@ -229,22 +235,28 @@ std::vector<DriveData> RemovableDriveManager::search_for_removable_drives() cons
|
||||
|
||||
#else
|
||||
|
||||
//search /media/* folder
|
||||
search_for_drives_internal::search_path("/media/*", "/media", current_drives);
|
||||
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 {
|
||||
//search /media/* folder
|
||||
search_for_drives_internal::search_path("/media/*", "/media", current_drives);
|
||||
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
}
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_for_drives_internal::search_path(path, pp, current_drives);
|
||||
#endif
|
||||
|
||||
return current_drives;
|
||||
@ -441,7 +453,10 @@ RemovableDriveManager::RemovableDrivesStatus RemovableDriveManager::status()
|
||||
RemovableDriveManager::RemovableDrivesStatus out;
|
||||
{
|
||||
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
||||
out.has_eject = this->find_last_save_path_drive_data() != m_current_drives.end();
|
||||
out.has_eject =
|
||||
// Cannot control eject on Chromium.
|
||||
platform_flavor() != PlatformFlavor::LinuxOnChromium &&
|
||||
this->find_last_save_path_drive_data() != m_current_drives.end();
|
||||
out.has_removable_drives = ! m_current_drives.empty();
|
||||
}
|
||||
if (! out.has_eject)
|
||||
|
Loading…
Reference in New Issue
Block a user