mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-05-01 00:04:27 +08:00

CURA-5229 - Move @call_on_qt_thread to a separate module - Make sure that project writer runs on Qt thread because itself and the calls it makes can create new QObjects such as InstanceContainers, and this must happen on the Qt thread.
35 lines
1.5 KiB
Python
35 lines
1.5 KiB
Python
import threading
|
|
|
|
from cura.CuraApplication import CuraApplication
|
|
|
|
|
|
#
|
|
# HACK:
|
|
#
|
|
# In project loading, when override the existing machine is selected, the stacks and containers that are correctly
|
|
# active in the system will be overridden at runtime. Because the project loading is done in a different thread than
|
|
# the Qt thread, something else can kick in the middle of the process. One of them is the rendering. It will access
|
|
# the current stacks and container, which have not completely been updated yet, so Cura will crash in this case.
|
|
#
|
|
# This "@call_on_qt_thread" decorator makes sure that a function will always be called on the Qt thread (blocking).
|
|
# It is applied to the read() function of project loading so it can be guaranteed that only after the project loading
|
|
# process is completely done, everything else that needs to occupy the QT thread will be executed.
|
|
#
|
|
class InterCallObject:
|
|
def __init__(self):
|
|
self.finish_event = threading.Event()
|
|
self.result = None
|
|
|
|
|
|
def call_on_qt_thread(func):
|
|
def _call_on_qt_thread_wrapper(*args, **kwargs):
|
|
def _handle_call(ico, *args, **kwargs):
|
|
ico.result = func(*args, **kwargs)
|
|
ico.finish_event.set()
|
|
inter_call_object = InterCallObject()
|
|
new_args = tuple([inter_call_object] + list(args)[:])
|
|
CuraApplication.getInstance().callLater(_handle_call, *new_args, **kwargs)
|
|
inter_call_object.finish_event.wait()
|
|
return inter_call_object.result
|
|
return _call_on_qt_thread_wrapper
|