diff --git a/openlp/core/app.py b/openlp/core/app.py index eb15c69b7..1ecca85f3 100644 --- a/openlp/core/app.py +++ b/openlp/core/app.py @@ -38,7 +38,6 @@ from PyQt5 import QtCore, QtWidgets from openlp.core.common import is_macosx, is_win from openlp.core.common.applocation import AppLocation from openlp.core.common.i18n import LanguageManager, UiStrings, translate -from openlp.core.common.mixins import LogMixin from openlp.core.common.path import create_paths, copytree from openlp.core.common.registry import Registry from openlp.core.common.settings import Settings @@ -50,6 +49,7 @@ from openlp.core.ui.firsttimeform import FirstTimeForm from openlp.core.ui.firsttimelanguageform import FirstTimeLanguageForm from openlp.core.ui.mainwindow import MainWindow from openlp.core.ui.style import get_application_stylesheet +from openlp.core.server import Server from openlp.core.version import check_for_update, get_version __all__ = ['OpenLP', 'main'] @@ -58,7 +58,7 @@ __all__ = ['OpenLP', 'main'] log = logging.getLogger() -class OpenLP(QtWidgets.QApplication, LogMixin): +class OpenLP(QtWidgets.QApplication): """ The core application class. This class inherits from Qt's QApplication class in order to provide the core of the application. @@ -72,7 +72,7 @@ class OpenLP(QtWidgets.QApplication, LogMixin): """ self.is_event_loop_active = True result = QtWidgets.QApplication.exec() - self.shared_memory.detach() + self.server.close_server() return result def run(self, args): @@ -86,6 +86,7 @@ class OpenLP(QtWidgets.QApplication, LogMixin): # On Linux and FreeBSD, in order to set the WM_CLASS property for X11, we pass "OpenLP" in as a command line # argument. This interferes with files being passed in as command line arguments, so we remove it from the list. if 'OpenLP' in args: + print("remove2") args.remove('OpenLP') self.args.extend(args) # Decide how many screens we have and their size @@ -135,23 +136,20 @@ class OpenLP(QtWidgets.QApplication, LogMixin): self.main_window.app_startup() return self.exec() - def is_already_running(self): + @staticmethod + def is_already_running(): """ Look to see if OpenLP is already running and ask if a 2nd instance is to be started. """ - self.shared_memory = QtCore.QSharedMemory('OpenLP') - if self.shared_memory.attach(): - status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart, - QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | - QtWidgets.QMessageBox.No)) - if status == QtWidgets.QMessageBox.No: - return True - return False - else: - self.shared_memory.create(1) - return False + status = QtWidgets.QMessageBox.critical(None, UiStrings().Error, UiStrings().OpenLPStart, + QtWidgets.QMessageBox.StandardButtons(QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No)) + if status == QtWidgets.QMessageBox.No: + return True + return False - def is_data_path_missing(self): + @staticmethod + def is_data_path_missing(): """ Check if the data folder path exists. """ @@ -383,11 +381,18 @@ def main(args=None): Registry().set_flag('no_web_server', args.no_web_server) application.setApplicationVersion(get_version()['version']) # Check if an instance of OpenLP is already running. Quit if there is a running instance and the user only wants one - if application.is_already_running(): - sys.exit() + server = Server() + if server.is_another_instance_running(): + if server.is_already_running(): + server.post_to_server(qt_args) + server.close_server() + sys.exit() + else: + server.start_server() + application.server = server # If the custom data path is missing and the user wants to restore the data path, quit OpenLP. if application.is_data_path_missing(): - application.shared_memory.detach() + server.close_server() sys.exit() # Upgrade settings. settings = Settings() diff --git a/openlp/core/server.py b/openlp/core/server.py new file mode 100644 index 000000000..340f95054 --- /dev/null +++ b/openlp/core/server.py @@ -0,0 +1,101 @@ +# -*- coding: utf-8 -*- +# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4 + +############################################################################### +# OpenLP - Open Source Lyrics Projection # +# --------------------------------------------------------------------------- # +# Copyright (c) 2008-2018 OpenLP Developers # +# --------------------------------------------------------------------------- # +# This program is free software; you can redistribute it and/or modify it # +# under the terms of the GNU General Public License as published by the Free # +# Software Foundation; version 2 of the License. # +# # +# This program is distributed in the hope that it will be useful, but WITHOUT # +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # +# more details. # +# # +# You should have received a copy of the GNU General Public License along # +# with this program; if not, write to the Free Software Foundation, Inc., 59 # +# Temple Place, Suite 330, Boston, MA 02111-1307 USA # +############################################################################### + + +from PyQt5 import QtCore +from PyQt5 import QtNetwork + +from openlp.core.common.mixins import LogMixin + + +class Server(QtCore.QObject, LogMixin): + """ + The local server to handle OpenLP running in more than one instance and allows file + handles to be transferred from the new to the existing one. + """ + + def is_another_instance_running(self): + self._id = 'OpenLPDual' + # Is there another instance running? + self._outSocket = QtNetwork.QLocalSocket() + self._outSocket.connectToServer(self._id) + return self._outSocket.waitForConnected() + + def post_to_server(self, args): + print(args) + if 'OpenLP' in args: + print("remove1") + args.remove('OpenLP') + # Yes, there is. + print("isRunning") + self._outStream = QtCore.QTextStream(self._outSocket) + self._outStream.setCodec('UTF-8') + self._outSocket.write(str.encode("".join(args))) + if not self._outSocket.waitForBytesWritten(10): + raise Exception(str(self._outSocket.errorString())) + self._outSocket.disconnectFromServer() + return False + + def start_server(self): + # No, there isn't. + print("No it is not") + self._outSocket = None + self._outStream = None + self._inSocket = None + self._inStream = None + self._server = QtNetwork.QLocalServer() + self._server.listen(self._id) + self._server.newConnection.connect(self._on_new_connection) + return True + + def _on_new_connection(self): + """ + Handle a new connection to the server + :return: + """ + if self._inSocket: + self._inSocket.readyRead.disconnect(self._on_ready_read) + self._inSocket = self._server.nextPendingConnection() + if not self._inSocket: + return + self._inStream = QtCore.QTextStream(self._inSocket) + self._inStream.setCodec('UTF-8') + self._inSocket.readyRead.connect(self._on_ready_read) + + def _on_ready_read(self): + """ + Read a record passed to the server and load a service + :return: + """ + while True: + msg = self._inStream.readLine() + if msg: + self.log_debug("socket msg = " + msg) + Registry().get('service_manager').on_load_service_clicked(msg) + + def close_server(self): + """ + Shutdown to local socket server + :return: + """ + if self._server: + self._server.close() \ No newline at end of file diff --git a/openlp/core/ui/servicemanager.py b/openlp/core/ui/servicemanager.py index 2e5d29e4d..54ce48251 100644 --- a/openlp/core/ui/servicemanager.py +++ b/openlp/core/ui/servicemanager.py @@ -434,6 +434,7 @@ class ServiceManager(QtWidgets.QWidget, RegistryBase, Ui_ServiceManager, LogMixi :param load_file: The service file to the loaded. Will be None is from menu so selection will be required. """ + print(load_file) if self.is_modified(): result = self.save_modified_service() if result == QtWidgets.QMessageBox.Cancel: