cura_app.py 5.8 KB

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