diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt
index 505c8f0f2..40d74159d 100644
--- a/src/slic3r/CMakeLists.txt
+++ b/src/slic3r/CMakeLists.txt
@@ -207,6 +207,8 @@ 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
diff --git a/src/slic3r/GUI/GUI_Init.cpp b/src/slic3r/GUI/GUI_Init.cpp
index 839782741..3c77f3335 100644
--- a/src/slic3r/GUI/GUI_Init.cpp
+++ b/src/slic3r/GUI/GUI_Init.cpp
@@ -9,6 +9,7 @@
 #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>
@@ -36,6 +37,8 @@ int GUI_Run(GUI_InitParams &params)
     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) {
diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp
index 9a1eecc11..8e8774036 100644
--- a/src/slic3r/GUI/OpenGLManager.cpp
+++ b/src/slic3r/GUI/OpenGLManager.cpp
@@ -4,6 +4,7 @@
 #include "GUI.hpp"
 #include "I18N.hpp"
 #include "3DScene.hpp"
+#include "slic3r/Utils/Platform.hpp"
 
 #include <GL/glew.h>
 
@@ -256,13 +257,6 @@ bool OpenGLManager::init_gl()
         }
 
         if (valid_version) {
-#ifdef __linux__
-            if (s_gl_info.get_renderer() == "virgl")
-                // Disable multi-sampling with virgl (VirtualGL) on Linux.
-                // Namely, on ChromeOS virgl flips red/blue channels at least on some computers with multi-sampling enabled.
-                // It seems it is sufficient to disable multi-sampling after the OpenGL context is created.
-                s_multisample = EMultisampleState::Disabled;
-#endif // __linux__
             // load shaders
             auto [result, error] = m_shaders_manager.init();
             if (!result) {
@@ -326,7 +320,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() != Platform::Linux || 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");
 }
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 65b4b7b28..f131c244f 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -75,6 +75,7 @@
 #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"
@@ -3681,7 +3682,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() != Platform::Linux || 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);
diff --git a/src/slic3r/GUI/RemovableDriveManager.cpp b/src/slic3r/GUI/RemovableDriveManager.cpp
index 85d91382a..c200956e1 100644
--- a/src/slic3r/GUI/RemovableDriveManager.cpp
+++ b/src/slic3r/GUI/RemovableDriveManager.cpp
@@ -1,4 +1,5 @@
 #include "RemovableDriveManager.hpp"
+#include "slic3r/Utils/Platform.hpp"
 #include <libslic3r/libslic3r.h>
 
 #include <boost/nowide/convert.hpp>
@@ -231,25 +232,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() == Platform::Linux && 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);
+	}
 
-    // ChromeOS specific: search /mnt/chromeos/removable/* folder
-	search_for_drives_internal::search_path("/mnt/chromeos/removable/*", "/mnt/chromeos/removable", current_drives);
 #endif
 
 	return current_drives;
@@ -446,7 +450,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() != Platform::Linux || 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)