From cf610080b9744691a2927a9f869c25eec2bba546 Mon Sep 17 00:00:00 2001 From: "Denilson M. Amorim" Date: Sat, 14 Nov 2015 20:12:19 -0300 Subject: [PATCH] Squash: Single instance and pop up old instance --- src/bitmessagemain.py | 2 +- src/bitmessageqt/__init__.py | 85 +++++++++++++++++++++++++++++++++--- src/singleton.py | 16 ++++--- 3 files changed, 91 insertions(+), 12 deletions(-) diff --git a/src/bitmessagemain.py b/src/bitmessagemain.py index daae1af9..a636730d 100755 --- a/src/bitmessagemain.py +++ b/src/bitmessagemain.py @@ -144,7 +144,7 @@ class Main: shared.daemon = daemon # is the application already running? If yes then exit. - thisapp = singleton.singleinstance() + thisapp = singleton.singleinstance("", daemon) import upnp upnp.createPortMapping() diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py index 9ac08d46..382a5f0d 100644 --- a/src/bitmessageqt/__init__.py +++ b/src/bitmessageqt/__init__.py @@ -56,10 +56,23 @@ import subprocess import datetime from helper_sql import * import l10n -import types -from utils import * -from collections import OrderedDict -from account import * + +try: + from PyQt4 import QtCore, QtGui + from PyQt4.QtCore import * + from PyQt4.QtGui import * + from PyQt4.QtNetwork import QLocalSocket, QLocalServer + +except Exception as err: + print 'PyBitmessage requires PyQt unless you want to run it as a daemon and interact with it using the API. You can download it from http://www.riverbankcomputing.com/software/pyqt/download or by searching Google for \'PyQt Download\' (without quotes).' + print 'Error message:', err + sys.exit() + +try: + _encoding = QtGui.QApplication.UnicodeUTF8 +except AttributeError: + print 'QtGui.QApplication.UnicodeUTF8 error:', err + def _translate(context, text): return QtGui.QApplication.translate(context, text) @@ -4483,8 +4496,70 @@ class UISignaler(QThread): sys.stderr.write( 'Command sent to UISignaler not recognized: %s\n' % command) + +app = None +myapp = None + +class MySingleApplication(QApplication): + """ + Listener to allow our Qt form to get focus when another instance of the + application is open. + + Based off this nice reimplmentation of MySingleApplication: + http://stackoverflow.com/a/12712362/2679626 + """ + + # Unique identifier for this application + uuid = '6ec0149b-96e1-4be1-93ab-1465fb3ebf7c' + + def __init__(self, *argv): + super(MySingleApplication, self).__init__(*argv) + id = MySingleApplication.uuid + + self.server = None + self.is_running = False + + socket = QLocalSocket() + socket.connectToServer(id) + self.is_running = socket.waitForConnected() + + # Cleanup past crashed servers + if not self.is_running: + if socket.error() == QLocalSocket.ConnectionRefusedError: + socket.disconnectFromServer() + QLocalServer.removeServer(id) + + socket.abort() + + # Checks if there's an instance of the local server id running + if self.is_running: + # This should be ignored, singleton.py will take care of exiting me. + pass + else: + # Nope, create a local server with this id and assign on_new_connection + # for whenever a second instance tries to run focus the application. + self.server = QLocalServer() + self.server.listen(id) + self.server.newConnection.connect(self.on_new_connection) + + def __del__(self): + if self.server: + self.server.close() + + def on_new_connection(self): + global myapp + if myapp: + myapp.appIndicatorShow() + +def init(): + global app + if not app: + app = MySingleApplication(sys.argv) + return app + def run(): - app = QtGui.QApplication(sys.argv) + global myapp + app = init() change_translation(l10n.getTranslationLanguage()) app.setStyleSheet("QStatusBar::item { border: 0px solid black }") myapp = MyForm() diff --git a/src/singleton.py b/src/singleton.py index ee5c3077..f3124424 100644 --- a/src/singleton.py +++ b/src/singleton.py @@ -3,22 +3,26 @@ import sys import os import errno -import tempfile +import shared from multiprocessing import Process - class singleinstance: """ - Implements a single instance application by creating a lock file based on the full path to the script file. + Implements a single instance application by creating a lock file at appdata. This is based upon the singleton class from tendo https://github.com/pycontribs/tendo which is under the Python Software Foundation License version 2 """ - def __init__(self, flavor_id=""): + def __init__(self, flavor_id="", daemon=False): import sys self.initialized = False - basename = os.path.splitext(os.path.abspath(sys.argv[0]))[0].replace("/", "-").replace(":", "").replace("\\", "-") + '-%s' % flavor_id + '.lock' - self.lockfile = os.path.normpath(tempfile.gettempdir() + '/' + basename) + self.daemon = daemon; + self.lockfile = os.path.normpath(os.path.join(shared.appdata, 'singleton%s.lock' % flavor_id)) + + if not self.daemon: + # Tells the already running (if any) application to get focus. + import bitmessageqt + bitmessageqt.init() if sys.platform == 'win32': try: