cura_app.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. #!/usr/bin/env python3
  2. # Copyright (c) 2018 Ultimaker B.V.
  3. # Cura is released under the terms of the LGPLv3 or higher.
  4. import argparse
  5. import os
  6. import sys
  7. from UM.Platform import Platform
  8. parser = argparse.ArgumentParser(prog = "cura",
  9. add_help = False)
  10. parser.add_argument('--debug',
  11. action='store_true',
  12. default = False,
  13. help = "Turn on the debug mode by setting this option."
  14. )
  15. parser.add_argument('--trigger-early-crash',
  16. dest = 'trigger_early_crash',
  17. action = 'store_true',
  18. default = False,
  19. help = "FOR TESTING ONLY. Trigger an early crash to show the crash dialog."
  20. )
  21. known_args = vars(parser.parse_known_args()[0])
  22. if not known_args["debug"]:
  23. def get_cura_dir_path():
  24. if Platform.isWindows():
  25. return os.path.expanduser("~/AppData/Roaming/cura")
  26. elif Platform.isLinux():
  27. return os.path.expanduser("~/.local/share/cura")
  28. elif Platform.isOSX():
  29. return os.path.expanduser("~/Library/Logs/cura")
  30. if hasattr(sys, "frozen"):
  31. dirpath = get_cura_dir_path()
  32. os.makedirs(dirpath, exist_ok = True)
  33. sys.stdout = open(os.path.join(dirpath, "stdout.log"), "w", encoding = "utf-8")
  34. sys.stderr = open(os.path.join(dirpath, "stderr.log"), "w", encoding = "utf-8")
  35. import platform
  36. import faulthandler
  37. #WORKAROUND: GITHUB-88 GITHUB-385 GITHUB-612
  38. if Platform.isLinux(): # Needed for platform.linux_distribution, which is not available on Windows and OSX
  39. # For Ubuntu: https://bugs.launchpad.net/ubuntu/+source/python-qt4/+bug/941826
  40. linux_distro_name = platform.linux_distribution()[0].lower()
  41. # The workaround is only needed on Ubuntu+NVidia drivers. Other drivers are not affected, but fine with this fix.
  42. try:
  43. import ctypes
  44. from ctypes.util import find_library
  45. libGL = find_library("GL")
  46. ctypes.CDLL(libGL, ctypes.RTLD_GLOBAL)
  47. except:
  48. # GLES-only systems (e.g. ARM Mali) do not have libGL, ignore error
  49. pass
  50. # When frozen, i.e. installer version, don't let PYTHONPATH mess up the search path for DLLs.
  51. if Platform.isWindows() and hasattr(sys, "frozen"):
  52. try:
  53. del os.environ["PYTHONPATH"]
  54. except KeyError:
  55. pass
  56. # WORKAROUND: GITHUB-704 GITHUB-708
  57. # It looks like setuptools creates a .pth file in
  58. # the default /usr/lib which causes the default site-packages
  59. # to be inserted into sys.path before PYTHONPATH.
  60. # This can cause issues such as having libsip loaded from
  61. # the system instead of the one provided with Cura, which causes
  62. # incompatibility issues with libArcus
  63. if "PYTHONPATH" in os.environ.keys(): # If PYTHONPATH is used
  64. PYTHONPATH = os.environ["PYTHONPATH"].split(os.pathsep) # Get the value, split it..
  65. PYTHONPATH.reverse() # and reverse it, because we always insert at 1
  66. for PATH in PYTHONPATH: # Now beginning with the last PATH
  67. PATH_real = os.path.realpath(PATH) # Making the the path "real"
  68. if PATH_real in sys.path: # This should always work, but keep it to be sure..
  69. sys.path.remove(PATH_real)
  70. sys.path.insert(1, PATH_real) # Insert it at 1 after os.curdir, which is 0.
  71. def exceptHook(hook_type, value, traceback):
  72. from cura.CrashHandler import CrashHandler
  73. from cura.CuraApplication import CuraApplication
  74. has_started = False
  75. if CuraApplication.Created:
  76. has_started = CuraApplication.getInstance().started
  77. #
  78. # When the exception hook is triggered, the QApplication may not have been initialized yet. In this case, we don't
  79. # have an QApplication to handle the event loop, which is required by the Crash Dialog.
  80. # The flag "CuraApplication.Created" is set to True when CuraApplication finishes its constructor call.
  81. #
  82. # Before the "started" flag is set to True, the Qt event loop has not started yet. The event loop is a blocking
  83. # call to the QApplication.exec_(). In this case, we need to:
  84. # 1. Remove all scheduled events so no more unnecessary events will be processed, such as loading the main dialog,
  85. # loading the machine, etc.
  86. # 2. Start the Qt event loop with exec_() and show the Crash Dialog.
  87. #
  88. # If the application has finished its initialization and was running fine, and then something causes a crash,
  89. # we run the old routine to show the Crash Dialog.
  90. #
  91. from PyQt5.Qt import QApplication
  92. if CuraApplication.Created:
  93. _crash_handler = CrashHandler(hook_type, value, traceback, has_started)
  94. if CuraApplication.splash is not None:
  95. CuraApplication.splash.close()
  96. if not has_started:
  97. CuraApplication.getInstance().removePostedEvents(None)
  98. _crash_handler.early_crash_dialog.show()
  99. sys.exit(CuraApplication.getInstance().exec_())
  100. else:
  101. _crash_handler.show()
  102. else:
  103. application = QApplication(sys.argv)
  104. application.removePostedEvents(None)
  105. _crash_handler = CrashHandler(hook_type, value, traceback, has_started)
  106. # This means the QtApplication could be created and so the splash screen. Then Cura closes it
  107. if CuraApplication.splash is not None:
  108. CuraApplication.splash.close()
  109. _crash_handler.early_crash_dialog.show()
  110. sys.exit(application.exec_())
  111. if not known_args["debug"]:
  112. sys.excepthook = exceptHook
  113. # Workaround for a race condition on certain systems where there
  114. # is a race condition between Arcus and PyQt. Importing Arcus
  115. # first seems to prevent Sip from going into a state where it
  116. # tries to create PyQt objects on a non-main thread.
  117. import Arcus #@UnusedImport
  118. import cura.CuraApplication
  119. import cura.Settings.CuraContainerRegistry
  120. faulthandler.enable()
  121. # Force an instance of CuraContainerRegistry to be created and reused later.
  122. cura.Settings.CuraContainerRegistry.CuraContainerRegistry.getInstance()
  123. # This pre-start up check is needed to determine if we should start the application at all.
  124. if not cura.CuraApplication.CuraApplication.preStartUp(parser = parser, parsed_command_line = known_args):
  125. sys.exit(0)
  126. app = cura.CuraApplication.CuraApplication.getInstance(parser = parser, parsed_command_line = known_args)
  127. app.run()