mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-16 14:05:57 +08:00
Merge branch 'single_instance'
This commit is contained in:
commit
71d2990ca9
@ -1,5 +1,7 @@
|
|||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
from PyQt5.QtNetwork import QLocalServer
|
||||||
|
from PyQt5.QtNetwork import QLocalSocket
|
||||||
|
|
||||||
from UM.Qt.QtApplication import QtApplication
|
from UM.Qt.QtApplication import QtApplication
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
@ -59,7 +61,8 @@ import numpy
|
|||||||
import copy
|
import copy
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import os
|
import os
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
|
||||||
numpy.seterr(all="ignore")
|
numpy.seterr(all="ignore")
|
||||||
|
|
||||||
@ -420,13 +423,99 @@ class CuraApplication(QtApplication):
|
|||||||
|
|
||||||
self._plugins_loaded = True
|
self._plugins_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
def addCommandLineOptions(self, parser):
|
def addCommandLineOptions(self, parser):
|
||||||
super().addCommandLineOptions(parser)
|
super().addCommandLineOptions(parser)
|
||||||
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
parser.add_argument("file", nargs="*", help="Files to load after starting the application.")
|
||||||
|
parser.add_argument("--single-instance", action="store_true", default=False)
|
||||||
|
|
||||||
|
# Set up a local socket server which listener which coordinates single instances Curas and accepts commands.
|
||||||
|
def _setUpSingleInstanceServer(self):
|
||||||
|
if self.getCommandLineOption("single_instance", False):
|
||||||
|
self.__single_instance_server = QLocalServer()
|
||||||
|
self.__single_instance_server.newConnection.connect(self._singleInstanceServerNewConnection)
|
||||||
|
self.__single_instance_server.listen("ultimaker-cura")
|
||||||
|
|
||||||
|
def _singleInstanceServerNewConnection(self):
|
||||||
|
Logger.log("i", "New connection recevied on our single-instance server")
|
||||||
|
remote_cura_connection = self.__single_instance_server.nextPendingConnection()
|
||||||
|
|
||||||
|
if remote_cura_connection is not None:
|
||||||
|
def readCommands():
|
||||||
|
line = remote_cura_connection.readLine()
|
||||||
|
while len(line) != 0: # There is also a .canReadLine()
|
||||||
|
try:
|
||||||
|
Logger.log('d', "JSON command: " + str(line, encoding="ASCII"))
|
||||||
|
payload = json.loads(str(line, encoding="ASCII").strip())
|
||||||
|
command = payload["command"]
|
||||||
|
|
||||||
|
# Command: Remove all models from the build plate.
|
||||||
|
if command == "clear-all":
|
||||||
|
self.deleteAll()
|
||||||
|
|
||||||
|
# Command: Load a model file
|
||||||
|
elif command == "open":
|
||||||
|
self._openFile(payload["filePath"])
|
||||||
|
# FIXME ^ this method is async and we really should wait until
|
||||||
|
# the file load is complete before processing more commands.
|
||||||
|
|
||||||
|
# Command: Activate the window and bring it to the top.
|
||||||
|
elif command == "focus":
|
||||||
|
self.getMainWindow().raise_()
|
||||||
|
self.focusWindow()
|
||||||
|
|
||||||
|
else:
|
||||||
|
Logger.log("w", "Received an unrecognized command " + str(command))
|
||||||
|
except json.decoder.JSONDecodeError as ex:
|
||||||
|
Logger.log("w", "Unable to parse JSON command in _singleInstanceServerNewConnection(): " + repr(ex))
|
||||||
|
line = remote_cura_connection.readLine()
|
||||||
|
|
||||||
|
remote_cura_connection.readyRead.connect(readCommands)
|
||||||
|
remote_cura_connection.disconnected.connect(readCommands) # Get any last commands before it is destroyed.
|
||||||
|
|
||||||
|
## Perform any checks before creating the main application.
|
||||||
|
#
|
||||||
|
# This should be called directly before creating an instance of CuraApplication.
|
||||||
|
# \returns \type{bool} True if the whole Cura app should continue running.
|
||||||
|
@classmethod
|
||||||
|
def preStartUp(cls):
|
||||||
|
# Peek the arguments and look for the 'single-instance' flag.
|
||||||
|
parser = argparse.ArgumentParser(prog="cura") # pylint: disable=bad-whitespace
|
||||||
|
CuraApplication.addCommandLineOptions(parser)
|
||||||
|
parsed_command_line = vars(parser.parse_args())
|
||||||
|
|
||||||
|
if "single_instance" in parsed_command_line and parsed_command_line["single_instance"]:
|
||||||
|
Logger.log("i", "Checking for the presence of an ready running Cura instance.")
|
||||||
|
single_instance_socket = QLocalSocket()
|
||||||
|
single_instance_socket.connectToServer("ultimaker-cura")
|
||||||
|
single_instance_socket.waitForConnected()
|
||||||
|
if single_instance_socket.state() == QLocalSocket.ConnectedState:
|
||||||
|
Logger.log("i", "Connection has been made to the single-instance Cura socket.")
|
||||||
|
|
||||||
|
# Protocol is one line of JSON terminated with a carriage return.
|
||||||
|
# "command" field is required and holds the name of the command to execute.
|
||||||
|
# Other fields depend on the command.
|
||||||
|
|
||||||
|
payload = {"command": "clear-all"}
|
||||||
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
||||||
|
|
||||||
|
payload = {"command": "focus"}
|
||||||
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
||||||
|
|
||||||
|
if len(parsed_command_line["file"]) != 0:
|
||||||
|
for filename in parsed_command_line["file"]:
|
||||||
|
payload = {"command": "open", "filePath": filename}
|
||||||
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ASCII"))
|
||||||
|
single_instance_socket.flush()
|
||||||
|
single_instance_socket.close()
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
self.showSplashMessage(self._i18n_catalog.i18nc("@info:progress", "Setting up scene..."))
|
||||||
|
|
||||||
|
self._setUpSingleInstanceServer()
|
||||||
|
|
||||||
controller = self.getController()
|
controller = self.getController()
|
||||||
|
|
||||||
controller.setActiveView("SolidView")
|
controller.setActiveView("SolidView")
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import platform
|
import platform
|
||||||
@ -58,5 +57,9 @@ if Platform.isWindows() and hasattr(sys, "frozen"):
|
|||||||
# Force an instance of CuraContainerRegistry to be created and reused later.
|
# Force an instance of CuraContainerRegistry to be created and reused later.
|
||||||
cura.Settings.CuraContainerRegistry.getInstance()
|
cura.Settings.CuraContainerRegistry.getInstance()
|
||||||
|
|
||||||
|
# This prestart up check is needed to determine if we should start the application at all.
|
||||||
|
if not cura.CuraApplication.CuraApplication.preStartUp():
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
app = cura.CuraApplication.CuraApplication.getInstance()
|
app = cura.CuraApplication.CuraApplication.getInstance()
|
||||||
app.run()
|
app.run()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user