Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_splitted_vbuffer
This commit is contained in:
commit
2e6a0f1ae3
11 changed files with 182 additions and 45 deletions
46
cmake/modules/FindGTK3.cmake
Normal file
46
cmake/modules/FindGTK3.cmake
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# - Try to find GTK+ 3
|
||||||
|
# Once done, this will define
|
||||||
|
#
|
||||||
|
# GTK3_FOUND - system has GTK+ 3.
|
||||||
|
# GTK3_INCLUDE_DIRS - the GTK+ 3. include directories
|
||||||
|
# GTK3_LIBRARIES - link these to use GTK+ 3.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||||
|
# Copyright (C) 2013 Igalia S.L.
|
||||||
|
#
|
||||||
|
# Redistribution and use in source and binary forms, with or without
|
||||||
|
# modification, are permitted provided that the following conditions
|
||||||
|
# are met:
|
||||||
|
# 1. Redistributions of source code must retain the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer.
|
||||||
|
# 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
# notice, this list of conditions and the following disclaimer in the
|
||||||
|
# documentation and/or other materials provided with the distribution.
|
||||||
|
#
|
||||||
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||||
|
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||||
|
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||||
|
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
find_package(PkgConfig)
|
||||||
|
pkg_check_modules(GTK3 QUIET gtk+-3.0)
|
||||||
|
set(VERSION_OK TRUE)
|
||||||
|
if (GTK3_VERSION)
|
||||||
|
if (GTK3_FIND_VERSION_EXACT)
|
||||||
|
if (NOT("${GTK3_FIND_VERSION}" VERSION_EQUAL "${GTK3_VERSION}"))
|
||||||
|
set(VERSION_OK FALSE)
|
||||||
|
endif ()
|
||||||
|
else ()
|
||||||
|
if ("${GTK3_VERSION}" VERSION_LESS "${GTK3_FIND_VERSION}")
|
||||||
|
set(VERSION_OK FALSE)
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
endif ()
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GTK3 DEFAULT_MSG GTK3_INCLUDE_DIRS GTK3_LIBRARIES VERSION_OK)
|
|
@ -255,3 +255,12 @@ endif ()
|
||||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||||
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# We need to implement some hacks for wxWidgets and touch the underlying GTK
|
||||||
|
# layer and sub-libraries. This forces us to use the include locations of these
|
||||||
|
# libraries. No need to link to them, wxWidgets does that already.
|
||||||
|
# See PresetComboBox.cpp for the includes and subsequent workarounds.
|
||||||
|
if (UNIX AND NOT APPLE)
|
||||||
|
find_package(GTK${SLIC3R_GTK} REQUIRED)
|
||||||
|
target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS})
|
||||||
|
endif ()
|
||||||
|
|
|
@ -2996,6 +2996,7 @@ void GLCanvas3D::on_render_timer(wxTimerEvent& evt)
|
||||||
}
|
}
|
||||||
//render();
|
//render();
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
|
wxWakeUpIdle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GLCanvas3D::request_extra_frame_delayed(int miliseconds)
|
void GLCanvas3D::request_extra_frame_delayed(int miliseconds)
|
||||||
|
|
|
@ -16,11 +16,26 @@
|
||||||
#include <boost/nowide/iostream.hpp>
|
#include <boost/nowide/iostream.hpp>
|
||||||
#include <boost/nowide/convert.hpp>
|
#include <boost/nowide/convert.hpp>
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
#include <signal.h>
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
int GUI_Run(GUI_InitParams ¶ms)
|
int GUI_Run(GUI_InitParams ¶ms)
|
||||||
{
|
{
|
||||||
|
#if __APPLE__
|
||||||
|
// On OSX, we use boost::process::spawn() to launch new instances of PrusaSlicer from another PrusaSlicer.
|
||||||
|
// boost::process::spawn() sets SIGCHLD to SIGIGN for the child process, thus if a child PrusaSlicer spawns another
|
||||||
|
// subprocess and the subrocess dies, the child PrusaSlicer will not receive information on end of subprocess
|
||||||
|
// (posix waitpid() call will always fail).
|
||||||
|
// https://jmmv.dev/2008/10/boostprocess-and-sigchld.html
|
||||||
|
// The child instance of PrusaSlicer has to reset SIGCHLD to its default, so that posix waitpid() and similar continue to work.
|
||||||
|
// See GH issue #5507
|
||||||
|
signal(SIGCHLD, SIG_DFL);
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
try {
|
try {
|
||||||
GUI::GUI_App* gui = new GUI::GUI_App(params.start_as_gcodeviewer ? GUI::GUI_App::EAppMode::GCodeViewer : GUI::GUI_App::EAppMode::Editor);
|
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) {
|
if (gui->get_app_mode() != GUI::GUI_App::EAppMode::GCodeViewer) {
|
||||||
|
|
|
@ -1233,11 +1233,11 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
|
||||||
|
|
||||||
if (this->activate_existing(notification.get())) {
|
if (this->activate_existing(notification.get())) {
|
||||||
m_pop_notifications.back()->update(notification->get_data());
|
m_pop_notifications.back()->update(notification->get_data());
|
||||||
canvas.request_extra_frame();
|
canvas.request_extra_frame_delayed(33);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
m_pop_notifications.emplace_back(std::move(notification));
|
m_pop_notifications.emplace_back(std::move(notification));
|
||||||
canvas.request_extra_frame();
|
canvas.request_extra_frame_delayed(33);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1387,15 +1387,19 @@ void NotificationManager::update_notifications()
|
||||||
if (!top_level_wnd->IsActive())
|
if (!top_level_wnd->IsActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static size_t last_size = m_pop_notifications.size();
|
//static size_t last_size = m_pop_notifications.size();
|
||||||
|
|
||||||
|
//request frames
|
||||||
|
int64_t next_render = std::numeric_limits<int64_t>::max();
|
||||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
|
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
|
||||||
std::unique_ptr<PopNotification>& notification = *it;
|
std::unique_ptr<PopNotification>& notification = *it;
|
||||||
|
notification->set_paused(m_hovered);
|
||||||
|
notification->update_state();
|
||||||
|
next_render = std::min<int64_t>(next_render, notification->next_render());
|
||||||
if (notification->get_state() == PopNotification::EState::Finished)
|
if (notification->get_state() == PopNotification::EState::Finished)
|
||||||
it = m_pop_notifications.erase(it);
|
it = m_pop_notifications.erase(it);
|
||||||
else {
|
else {
|
||||||
notification->set_paused(m_hovered);
|
|
||||||
notification->update_state();
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1436,16 +1440,11 @@ void NotificationManager::update_notifications()
|
||||||
if (m_requires_render)
|
if (m_requires_render)
|
||||||
m_requires_update = true;
|
m_requires_update = true;
|
||||||
*/
|
*/
|
||||||
//request frames
|
|
||||||
int64_t next_render = std::numeric_limits<int64_t>::max();
|
|
||||||
const int64_t max = std::numeric_limits<int64_t>::max();
|
|
||||||
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
|
|
||||||
next_render = std::min<int64_t>(next_render, notification->next_render());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (next_render == 0)
|
if (next_render == 0)
|
||||||
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
|
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(33); //few milliseconds to get from GLCanvas::render
|
||||||
else if (next_render < max)
|
else if (next_render < std::numeric_limits<int64_t>::max())
|
||||||
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render));
|
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -32,6 +32,14 @@
|
||||||
#include "PhysicalPrinterDialog.hpp"
|
#include "PhysicalPrinterDialog.hpp"
|
||||||
#include "SavePresetDialog.hpp"
|
#include "SavePresetDialog.hpp"
|
||||||
|
|
||||||
|
// A workaround for a set of issues related to text fitting into gtk widgets:
|
||||||
|
// See e.g.: https://github.com/prusa3d/PrusaSlicer/issues/4584
|
||||||
|
#if defined(__WXGTK20__) || defined(__WXGTK3__)
|
||||||
|
#include <glib-2.0/glib-object.h>
|
||||||
|
#include <pango-1.0/pango/pango-layout.h>
|
||||||
|
#include <gtk/gtk.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
using Slic3r::GUI::format_wxstr;
|
using Slic3r::GUI::format_wxstr;
|
||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
@ -179,6 +187,25 @@ void PresetComboBox::update_selection()
|
||||||
|
|
||||||
SetSelection(m_last_selected);
|
SetSelection(m_last_selected);
|
||||||
SetToolTip(GetString(m_last_selected));
|
SetToolTip(GetString(m_last_selected));
|
||||||
|
|
||||||
|
// A workaround for a set of issues related to text fitting into gtk widgets:
|
||||||
|
// See e.g.: https://github.com/prusa3d/PrusaSlicer/issues/4584
|
||||||
|
#if defined(__WXGTK20__) || defined(__WXGTK3__)
|
||||||
|
GList* cells = gtk_cell_layout_get_cells(GTK_CELL_LAYOUT(m_widget));
|
||||||
|
|
||||||
|
// 'cells' contains the GtkCellRendererPixBuf for the icon,
|
||||||
|
// 'cells->next' contains GtkCellRendererText for the text we need to ellipsize
|
||||||
|
if (!cells || !cells->next) return;
|
||||||
|
|
||||||
|
auto cell = static_cast<GtkCellRendererText *>(cells->next->data);
|
||||||
|
|
||||||
|
if (!cell) return;
|
||||||
|
|
||||||
|
g_object_set(G_OBJECT(cell), "ellipsize", PANGO_ELLIPSIZE_END, NULL);
|
||||||
|
|
||||||
|
// Only the list of cells must be freed, the renderer isn't ours to free
|
||||||
|
g_list_free(cells);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetComboBox::update(std::string select_preset_name)
|
void PresetComboBox::update(std::string select_preset_name)
|
||||||
|
|
|
@ -261,19 +261,31 @@ void RemovableDriveManager::eject_drive()
|
||||||
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
||||||
this->update();
|
this->update();
|
||||||
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
#endif // REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
||||||
|
#if __APPLE__
|
||||||
|
// If eject is still pending on the eject thread, wait until it finishes.
|
||||||
|
//FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
|
||||||
|
// to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
|
||||||
|
// finishes quickly.
|
||||||
|
this->eject_thread_finish();
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Ejecting started";
|
BOOST_LOG_TRIVIAL(info) << "Ejecting started";
|
||||||
|
|
||||||
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
DriveData drive_data;
|
||||||
auto it_drive_data = this->find_last_save_path_drive_data();
|
{
|
||||||
if (it_drive_data != m_current_drives.end()) {
|
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
||||||
std::string correct_path(m_last_save_path);
|
auto it_drive_data = this->find_last_save_path_drive_data();
|
||||||
#ifndef __APPLE__
|
if (it_drive_data == m_current_drives.end())
|
||||||
for (size_t i = 0; i < correct_path.size(); ++i)
|
return;
|
||||||
if (correct_path[i]==' ') {
|
drive_data = *it_drive_data;
|
||||||
correct_path = correct_path.insert(i,1,'\\');
|
}
|
||||||
++ i;
|
|
||||||
}
|
std::string correct_path(m_last_save_path);
|
||||||
|
#if __APPLE__
|
||||||
|
// On Apple, run the eject asynchronously on a worker thread, see the discussion at GH issue #4844.
|
||||||
|
m_eject_thread = new boost::thread([this, correct_path, drive_data]()
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
||||||
// there is no usable command in c++ so terminal command is used instead
|
// there is no usable command in c++ so terminal command is used instead
|
||||||
// but neither triggers "succesful safe removal messege"
|
// but neither triggers "succesful safe removal messege"
|
||||||
|
@ -296,31 +308,36 @@ void RemovableDriveManager::eject_drive()
|
||||||
// wait for command to finnish (blocks ui thread)
|
// wait for command to finnish (blocks ui thread)
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
child.wait(ec);
|
child.wait(ec);
|
||||||
|
bool success = false;
|
||||||
if (ec) {
|
if (ec) {
|
||||||
// The wait call can fail, as it did in https://github.com/prusa3d/PrusaSlicer/issues/5507
|
// The wait call can fail, as it did in https://github.com/prusa3d/PrusaSlicer/issues/5507
|
||||||
// It can happen even in cases where the eject is sucessful, but better report it as failed.
|
// It can happen even in cases where the eject is sucessful, but better report it as failed.
|
||||||
// We did not find a way to reliably retrieve the exit code of the process.
|
// We did not find a way to reliably retrieve the exit code of the process.
|
||||||
BOOST_LOG_TRIVIAL(error) << "boost::process::child::wait() failed during Ejection. State of Ejection is unknown. Error code: " << ec.value();
|
BOOST_LOG_TRIVIAL(error) << "boost::process::child::wait() failed during Ejection. State of Ejection is unknown. Error code: " << ec.value();
|
||||||
assert(m_callback_evt_handler);
|
} else {
|
||||||
if (m_callback_evt_handler)
|
int err = child.exit_code();
|
||||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
if (err) {
|
||||||
return;
|
BOOST_LOG_TRIVIAL(error) << "Ejecting failed. Exit code: " << err;
|
||||||
|
} else {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Ejecting finished";
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
int err = child.exit_code();
|
|
||||||
if (err) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "Ejecting failed. Exit code: " << err;
|
|
||||||
assert(m_callback_evt_handler);
|
|
||||||
if (m_callback_evt_handler)
|
|
||||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(*it_drive_data, false)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Ejecting finished";
|
|
||||||
|
|
||||||
assert(m_callback_evt_handler);
|
assert(m_callback_evt_handler);
|
||||||
if (m_callback_evt_handler)
|
if (m_callback_evt_handler)
|
||||||
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(std::move(*it_drive_data), true)));
|
wxPostEvent(m_callback_evt_handler, RemovableDriveEjectEvent(EVT_REMOVABLE_DRIVE_EJECTED, std::pair<DriveData, bool>(drive_data, success)));
|
||||||
m_current_drives.erase(it_drive_data);
|
if (success) {
|
||||||
|
// Remove the drive_data from m_current drives, searching by value, not by pointer, as m_current_drives may get modified during
|
||||||
|
// asynchronous execution on m_eject_thread.
|
||||||
|
tbb::mutex::scoped_lock lock(m_drives_mutex);
|
||||||
|
auto it = std::find(m_current_drives.begin(), m_current_drives.end(), drive_data);
|
||||||
|
if (it != m_current_drives.end())
|
||||||
|
m_current_drives.erase(it);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#if __APPLE__
|
||||||
|
);
|
||||||
|
#endif // __APPLE__
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
|
std::string RemovableDriveManager::get_removable_drive_path(const std::string &path)
|
||||||
|
@ -382,7 +399,11 @@ void RemovableDriveManager::init(wxEvtHandler *callback_evt_handler)
|
||||||
void RemovableDriveManager::shutdown()
|
void RemovableDriveManager::shutdown()
|
||||||
{
|
{
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
this->unregister_window_osx();
|
// If eject is still pending on the eject thread, wait until it finishes.
|
||||||
|
//FIXME while waiting for the eject thread to finish, the main thread is not pumping Cocoa messages, which may lead
|
||||||
|
// to blocking by the diskutil tool for a couple (up to 10) seconds. This is likely not critical, as the eject normally
|
||||||
|
// finishes quickly.
|
||||||
|
this->eject_thread_finish();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
#ifndef REMOVABLE_DRIVE_MANAGER_OS_CALLBACKS
|
||||||
|
@ -493,4 +514,15 @@ std::vector<DriveData>::const_iterator RemovableDriveManager::find_last_save_pat
|
||||||
[this](const DriveData &data){ return data.path == m_last_save_path; });
|
[this](const DriveData &data){ return data.path == m_last_save_path; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if __APPLE__
|
||||||
|
void RemovableDriveManager::eject_thread_finish()
|
||||||
|
{
|
||||||
|
if (m_eject_thread) {
|
||||||
|
m_eject_thread->join();
|
||||||
|
delete m_eject_thread;
|
||||||
|
m_eject_thread = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // __APPLE__
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
|
@ -132,6 +132,8 @@ private:
|
||||||
void eject_device(const std::string &path);
|
void eject_device(const std::string &path);
|
||||||
// Opaque pointer to RemovableDriveManagerMM
|
// Opaque pointer to RemovableDriveManagerMM
|
||||||
void *m_impl_osx;
|
void *m_impl_osx;
|
||||||
|
boost::thread *m_eject_thread { nullptr };
|
||||||
|
void eject_thread_finish();
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -501,7 +501,7 @@ void Tab::update_labels_colour()
|
||||||
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
|
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
|
||||||
opt.first == "compatible_prints" || opt.first == "compatible_printers" ) {
|
opt.first == "compatible_prints" || opt.first == "compatible_printers" ) {
|
||||||
if (m_colored_Label_colors.find(opt.first) != m_colored_Label_colors.end())
|
if (m_colored_Label_colors.find(opt.first) != m_colored_Label_colors.end())
|
||||||
*m_colored_Label_colors.at(opt.first) = *color;
|
m_colored_Label_colors.at(opt.first) = *color;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,7 +540,7 @@ void Tab::decorate()
|
||||||
|
|
||||||
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
|
if (opt.first == "bed_shape" || opt.first == "filament_ramming_parameters" ||
|
||||||
opt.first == "compatible_prints" || opt.first == "compatible_printers")
|
opt.first == "compatible_prints" || opt.first == "compatible_printers")
|
||||||
colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : m_colored_Label_colors.at(opt.first);
|
colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : &m_colored_Label_colors.at(opt.first);
|
||||||
|
|
||||||
if (!colored_label_clr) {
|
if (!colored_label_clr) {
|
||||||
field = get_field(opt.first);
|
field = get_field(opt.first);
|
||||||
|
@ -3553,8 +3553,8 @@ void Tab::create_line_with_widget(ConfigOptionsGroup* optgroup, const std::strin
|
||||||
line.widget = widget;
|
line.widget = widget;
|
||||||
line.label_path = path;
|
line.label_path = path;
|
||||||
|
|
||||||
m_colored_Label_colors[opt_key] = &m_default_text_clr;
|
m_colored_Label_colors[opt_key] = m_default_text_clr;
|
||||||
line.full_Label_color = m_colored_Label_colors[opt_key];
|
line.full_Label_color = &m_colored_Label_colors[opt_key];
|
||||||
|
|
||||||
optgroup->append_line(line);
|
optgroup->append_line(line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ public:
|
||||||
|
|
||||||
// map of option name -> wxColour (color of the colored label, associated with option)
|
// map of option name -> wxColour (color of the colored label, associated with option)
|
||||||
// Used for options which don't have corresponded field
|
// Used for options which don't have corresponded field
|
||||||
std::map<std::string, wxColour*> m_colored_Label_colors;
|
std::map<std::string, wxColour> m_colored_Label_colors;
|
||||||
|
|
||||||
// Counter for the updating (because of an update() function can have a recursive behavior):
|
// Counter for the updating (because of an update() function can have a recursive behavior):
|
||||||
// 1. increase value from the very beginning of an update() function
|
// 1. increase value from the very beginning of an update() function
|
||||||
|
|
|
@ -78,6 +78,12 @@ static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance
|
||||||
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
|
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
|
||||||
args.emplace_back("--single-instance");
|
args.emplace_back("--single-instance");
|
||||||
boost::process::spawn(bin_path, args);
|
boost::process::spawn(bin_path, args);
|
||||||
|
// boost::process::spawn() sets SIGCHLD to SIGIGN for the child process, thus if a child PrusaSlicer spawns another
|
||||||
|
// subprocess and the subrocess dies, the child PrusaSlicer will not receive information on end of subprocess
|
||||||
|
// (posix waitpid() call will always fail).
|
||||||
|
// https://jmmv.dev/2008/10/boostprocess-and-sigchld.html
|
||||||
|
// The child instance of PrusaSlicer has to reset SIGCHLD to its default, so that posix waitpid() and similar continue to work.
|
||||||
|
// See GH issue #5507
|
||||||
}
|
}
|
||||||
catch (const std::exception& ex) {
|
catch (const std::exception& ex) {
|
||||||
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
|
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
|
||||||
|
|
Loading…
Reference in a new issue