Ejemplo n.º 1
0
class QSingleApplication(QApplication):
    def singleStart(self, mainWindow):
        self.mainWindow = mainWindow
        # Socket
        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(self.applicationName(), QIODevice.WriteOnly)
    def connectToExistingApp(self):
        if len(sys.argv)>1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            QMessageBox.warning(None, self.tr("Already running"), self.tr("The program is already running."))
            # Quit application in 250 ms
            QTimer.singleShot(250, self.quit)
    def startApplication(self):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.applicationName()):
            self.m_server.newConnection.connect(self.getNewConnection)
            self.mainWindow.show()
        else:
            QMessageBox.critical(None, self.tr("Error"), self.tr("Error listening the socket."))
    def getNewConnection(self):
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)
    def readSocket(self):
        f = self.new_socket.readLine()
        self.mainWindow.getArgsFromOtherInstance(str(f))
        self.mainWindow.activateWindow()
        self.mainWindow.show()
Ejemplo n.º 2
0
    def startApplication(self, first_start=True):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.sock_file):
            if "--testnet" in sys.argv[1:]:
                print("Starting app... TESTNET MODE")
            else:
                print("Starting app...")
            self.appMain.run()
        else:
            if not first_start:
                print("Error listening the socket. App can't start!",
                      file=sys.stderr)
                QTimer.singleShot(250, self.quit)
                return

            # remove the listener path file and try to restart app one more time
            print("Error listening the socket. Try to restart application...",
                  file=sys.stderr)
            if sys.platform != 'win32':
                try:
                    os.unlink(self.sock_file)
                except Exception, err:
                    print(err, file=sys.stderr)

            QTimer.singleShot(250,
                              lambda: self.startApplication(first_start=False))
Ejemplo n.º 3
0
class QSingleApplication(QApplication):
    # Signal sent when another instance is launched with arguments
    argsReceived = QtCore.Signal((str, ))

    # Start the application,
    # either as a server (first instance) or as a client
    # others clients only send the argv they have been given and exit
    def singleStart(self, mainWindow):
        print "singleStart() function from QSingleApp got called."
        self.mainWindow = mainWindow
        # Socket
        self.m_socket = QLocalSocket()
        # Connected, error are signals that are being emitted
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(self.applicationName(),
                                      QIODevice.WriteOnly)

    # used for the very first instance to create the main window and start server
    def startApplication(self):
        self.m_server = QLocalServer()
        print "startApplication() function from QSingleApplication got called"
        # Returns bool (True on success). Tells server to listen for incoming connections on 'name'
        if self.m_server.listen(self.applicationName()):
            print "Server is listening .... startApplication() function from QSingleApp"
            self.m_server.newConnection.connect(self.getNewConnection)
            # After emitting a signal, connecting it to the UI class function
            self.argsReceived.connect(self.mainWindow.receive_args)
            self.mainWindow.show()
        else:
            QMessageBox.critical(None, self.tr("Error"),
                                 self.tr("Error listening the socket."))

    # used by later instances to send argv to the main instance
    def connectToExistingApp(self):
        if len(sys.argv) > 1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            print "exiting new app A"
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            print "exiting new app B"
            self.m_socket.write("--show")
            self.m_socket.bytesWritten.connect(self.quit)

    def getNewConnection(self):
        print "getNewConnection() was called"
        self.mainWindow.show()
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)

    def readSocket(self):
        print "readSocket() function in QSingleApplication.py"
        f = self.new_socket.readLine()
        self.argsReceived.emit(str(f))
Ejemplo n.º 4
0
 def startApplication(self):
     self.m_server = QLocalServer()
     print "startApplication() function from QSingleApplication got called"
     # Returns bool (True on success). Tells server to listen for incoming connections on 'name'
     if self.m_server.listen(self.applicationName()):
         print "Server is listening .... startApplication() function from QSingleApp"
         self.m_server.newConnection.connect(self.getNewConnection)
         # After emitting a signal, connecting it to the UI class function
         self.argsReceived.connect(self.mainWindow.receive_args)
         self.mainWindow.show()
     else:
         QMessageBox.critical(None, self.tr("Error"),
                              self.tr("Error listening the socket."))
Ejemplo n.º 5
0
 def startApplication(self):
     self.m_server = QLocalServer()
     if self.m_server.listen(self.applicationName()):
         self.m_server.newConnection.connect(self.getNewConnection)
         self.mainWindow.show()
     else:
         QMessageBox.critical(None, self.tr("Error"), self.tr("Error listening the socket."))
Ejemplo n.º 6
0
    def _create_server(self, try_remove=True):
        """
        Attempt to create a new local server and start listening.
        """
        if not self._server:
            self._server = QLocalServer(self)
            self._server.newConnection.connect(self._new_connection)

        if self._server.isListening():
            return True

        # If desired, remove the old server file.
        if try_remove:
            QLocalServer.removeServer(self._app_id)

        # Now, attempt to listen and return the success of that.
        return self._server.listen(self._app_id)
Ejemplo n.º 7
0
class QSingleApplication(QApplication):
    # Signal sent when another instance is launched with arguments
    argsReceived = QtCore.Signal((str,))

    # Start the application,
    # either as a server (first instance) or as a client
    # others clients only send the argv they have been given and exit
    def singleStart(self, mainWindow):
        self.mainWindow = mainWindow
        # Socket
        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(self.startApplication)
        self.m_socket.connectToServer(self.applicationName(), QIODevice.WriteOnly)

    # used for the very first instance to create the main window and start server
    def startApplication(self):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.applicationName()):
            self.m_server.newConnection.connect(self.getNewConnection)
            self.argsReceived.connect(self.mainWindow.receive_args)
            self.mainWindow.show()
        else:
            QMessageBox.critical(None, self.tr("Error"), self.tr("Error listening the socket."))

    # used by later instances to send argv to the main instance
    def connectToExistingApp(self):
        if len(sys.argv)>1 and sys.argv[1] is not None:
            self.m_socket.write(sys.argv[1])
            self.m_socket.bytesWritten.connect(self.quit)
        else:
            self.m_socket.write("--show")
            self.m_socket.bytesWritten.connect(self.quit)

    def getNewConnection(self):
        self.mainWindow.show()
        self.new_socket = self.m_server.nextPendingConnection()
        self.new_socket.readyRead.connect(self.readSocket)

    def readSocket(self):
        f = self.new_socket.readLine()
        self.argsReceived.emit(str(f))
Ejemplo n.º 8
0
class QSingleApplication(QApplication):
    sock_file = 'ryo_wallet_sock'
    if sys.platform == 'win32':
        sock_file = "\\\\.\\pipe\\%s" % sock_file
    elif sys.platform == 'darwin':
        sock_file = os.path.join(DATA_DIR, '.%s' % sock_file)
    else:
        sock_file = os.path.join(getSockDir(), sock_file)

    def singleStart(self, appMain):
        self.appMain = appMain
        # Socket
        self.m_socket = QLocalSocket()
        self.m_socket.connected.connect(self.connectToExistingApp)
        self.m_socket.error.connect(
            lambda: self.startApplication(first_start=True))
        self.m_socket.connectToServer(self.sock_file, QIODevice.WriteOnly)

    def connectToExistingApp(self):
        # Quit application in 250 ms
        QTimer.singleShot(250, self.quit)
        print("App is already running.", file=sys.stderr)

    def startApplication(self, first_start=True):
        self.m_server = QLocalServer()
        if self.m_server.listen(self.sock_file):
            if "--testnet" in sys.argv[1:]:
                print("Starting app... TESTNET MODE")
            else:
                print("Starting app...")
            self.appMain.run()
        else:
            if not first_start:
                print("Error listening the socket. App can't start!",
                      file=sys.stderr)
                QTimer.singleShot(250, self.quit)
                return

            # remove the listener path file and try to restart app one more time
            print("Error listening the socket. Try to restart application...",
                  file=sys.stderr)
            if sys.platform != 'win32':
                try:
                    os.unlink(self.sock_file)
                except Exception, err:
                    print(err, file=sys.stderr)

            QTimer.singleShot(250,
                              lambda: self.startApplication(first_start=False))
Ejemplo n.º 9
0
 def createStatusBar(self):
     """
     Create the status bar.
     """
     statusbar = self.statusBar
     # line and column number
     self.lineColNumber = QLabel(statusbar)
     self.lineColNumber.setText("")
     statusbar.addPermanentWidget(self.lineColNumber)
     statusbar.socketServer = QLocalServer()
     statusbar.socketServer.removeServer(self.infolog.socket)
     statusbar.socketServer.listen(self.infolog.socket)
     statusbar.socketServer.newConnection.connect(
         self.setupStatusConnection)
     self.log.info('Ready')
Ejemplo n.º 10
0
class QSingleApplication(QApplication):
    """
    This subclass of :class:`~PySide.QtGui.QApplication` ensures that only a
    single instance of an application will be run simultaneously, and provides
    a mechanism for new instances to send commands to the previously existing
    instance before the new instance closes.
    When running on Windows, QSingleApplication also listens for the
    ``WM_DWMCOMPOSITIONCHANGED`` message to allow styles utilizing Aero Glass
    to properly enable or disable Aero Glass on widgets when composition is
    enabled or disabled on a system-wide level.
    
    The application ID used to verify that the application is not already
    running can be customized by setting the ``app_id`` and ``session``
    variables of the QSingleApplication instance to the desired strings before
    using :attr:`already_running` or calling :func:`ensure_single` or
    :func:`send_message`.
    .. note::
        ``app_id`` and ``session`` will undergo additional processing and be
        converted into a :func:`UUID <uuid.uuid5>` before being utilized. If
        you *really* wish to use your own string, set ``_app_id``.
    """
    if sys.version_info.major == 3:
        messageReceived = Signal([dict], [list], [bool], [int], [float])
    else:
        messageReceived = Signal([dict], [list], [bool], [int], [long], [unicode], [float])
    compositionChanged = Signal()

    # Public Variables
    session = None
    app_id = None

    # Lock State Variables
    _app_id = None
    _mutex = None
    _lockfile = None
    _server = None
    _already = None

    def __init__(self, *args, **kwargs):
        if not args:
            args = (sys.argv,)
        super(QSingleApplication, self).__init__(*args, **kwargs)
        #QApplication.__init__(self, *args, **kwargs)

        # During shutdown, we can't rely on globals like os being still available.
        if os.name == "nt":
            self._close_lock = self._close_mutex
        else:
            self._close_lock = self._close_lockfile

        # If this is Windows, then _aeroglass is imported already, so hook up
        # to that.
#         if _aeroglass:
#             _aeroglass.manager.attach(self)

    def __del__(self):
        """
        Close the handle of our mutex if we have one, destroy any existing lock
        file, any gracefully close the QLocalServer.
        """

        self._close_lock()
        self._close_server()

    ##### Event Filtering #####################################################

    def winEventFilter(self, message):
        """
        Extend the built-in event filtering to handle the
        WM_DWMCOMPOSITIONCHANGED message on Windows.
        """
        if getattr(message, 'message', None) == WM_DWMCOMPOSITIONCHANGED:
            self.compositionChanged.emit()
        return QApplication.winEventFilter(self, message)

    ##### Lock Code ###########################################################

    @property
    def already_running(self):
        """ Whether or not the application is already running. """
        if self._already is None:
            # Attempt to acquire a lock.
            self._acquire_lock()

        return self._already

    def ensure_single(self, message=None):
        """
        Ensure that this is the only instance of the application running. If
        a previous instance is detected, send the provided message before
        raising a :class:`SystemExit` exception.
        If ``message`` is None, ``sys.argv[:1]`` will be used instead. Note
        that a false value *other* than None will result in no message being
        sent.
        """
        if self.already_running:
            if message is None:
                message = sys.argv[1:]
            if message:
                self.send_message(message)
            exit()

        # Still here? Keep being awesome.

    ##### Private Lock Code ###################################################

    def _acquire_lock(self):
        """
        Depending on the OS, either create a lockfile or use Mutex to obtain
        a lock. Also start the socket server.
        """
        if not self._app_id:
            self._build_app_id()

        if os.name == 'nt':
            result = self._create_mutex()
        else:
            result = self._create_lockfile()

        if result:
            self._create_server()
        self._already = not result

    def _build_app_id(self):
        """
        Create a unique application ID if necessary.
        """
        if not self.app_id:
            path, binary = os.path.split(os.path.abspath(sys.argv[0]))

            # Build the first part of the app_id.
            self.app_id = 'qsingleapp-%s-%s' % (binary, path)
            
#             if isinstance(self.app_id, unicode):
#                 self.app_id = self.app_id.encode('utf8')

        # Now, get the session ID.
        if not self.session:
            if os.name == 'nt':
                try:
                    sid = '%X' % getsid(os.getpid())
                except OSError:
                    sid = os.getenv('USERNAME')
            else:
                sid = os.getenv('USER')

            if profile.profile_path:
                sid = '%s-%s' % (profile.profile_path, sid)

#             if isinstance(sid, unicode):
#                 sid = sid.encode('utf8')

            self.session = sid

        self._app_id = str(uuid.uuid5(uuid.NAMESPACE_OID,
                                        self.app_id + self.session))

    ##### Mutex Code ##########################################################

    def _close_mutex(self, CloseHandle=windll.kernel32.CloseHandle):
        """
        If we have a mutex, try to close it.
        """
        if self._mutex:
            CloseHandle(self._mutex)
            self._mutex = None

    def _create_mutex(self):
        """
        Attempt to create a new mutex. Returns True if the mutex was acquired
        successfully, or False if the mutex is already in use.
        """
        mutex_name = c_wchar_p(self._app_id[:MAX_PATH])
        handle = windll.kernel32.CreateMutexW(None, c_bool(False), mutex_name)
        self._mutex = handle

        return not (not handle or GetLastError() == ERROR_ALREADY_EXISTS)

    ##### Lockfile Code #######################################################

    def _close_lockfile(self, unlink=os.unlink, close=os.close):
        """
        If a lockfile exists, delete it.
        """
        if self._lockfile:
            unlink(self._lockfile)
            close(self._lockfd)
            self._lockfile = None
            self._lockfd = None

    def _create_lockfile(self):
        """
        Attempt to create a lockfile in the user's temporary directory. This is
        one of the few things that doesn't obey the path functions of profile.
        """
        lockfile = os.path.abspath(os.path.join(QDir.tempPath(),
                                                u'%s.lock' % self._app_id))

        try:
            fd = os.open(lockfile, os.O_TRUNC | os.O_CREAT | os.O_RDWR)
            fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
            os.write(fd, "%d\n" % os.getpid())
        
        except (OSError, IOError) as e:
            if e.errno in (errno.EACCES, errno.EAGAIN):
                return False
            raise
        
        # We've got it.
        self._lockfd = fd
        self._lockfile = lockfile
        return True

    ##### The LocalServer #####################################################

    def _create_server(self, try_remove=True):
        """
        Attempt to create a new local server and start listening.
        """
        if not self._server:
            self._server = QLocalServer(self)
            self._server.newConnection.connect(self._new_connection)

        if self._server.isListening():
            return True

        # If desired, remove the old server file.
        if try_remove:
            QLocalServer.removeServer(self._app_id)

        # Now, attempt to listen and return the success of that.
        return self._server.listen(self._app_id)

    def _close_server(self):
        """
        Close the local server.
        """
        if self._server:
            try:
                if self._server.isListening():
                    self._server.close()
            except RuntimeError:
                pass
            self._server = None

    def _read_length(self, sock):
        if sock.bytesAvailable() < 4:
            return

        # Read the length.
        length = struct.unpack("!I", sock.read(4).data())[0]

        # If we don't have a length, just end now.
        if not length:
            sock.close()
            return

        # Set the next reader.
        if sock.bytesAvailable() == length:
            self._read_message(sock, length)
        else:
            sock.readyRead.disconnect()
            sock.readyRead.connect(partial(self._read_message, sock, length))

    def _read_message(self, sock, length):
        if sock.bytesAvailable() < length:
            return
		#TODO: enter switch
        message = sock.readAll().data().decode()
        message = json.loads(message)
        sock.close()
        self.messageReceived.emit(message)

    def _new_connection(self):
        """
        Accept a connection and read the message from it.
        """
        sock = self._server.nextPendingConnection()
        if not sock:
            return
        
        sock.readyRead.connect(partial(self._read_length, sock))

    def send_message(self, message, callback=None):
        """
        Attempt to send a message to the previously running instance of the
        application. Returns True if the message is sent successfully, or False
        otherwise.
        Alternatively, if a callback is provided the function will return
        immediately and the boolean will be sent to the callback instead.
        """
        message = json.dumps(message)
        if sys.version_info.major == 3:
            packedLen = struct.pack("!I", len(message)).decode()
        else:
            packedLen = struct.pack("!I", len(message))
        message = packedLen + message

        # Create a socket.
        sock = QLocalSocket(self)

        # Build our helper functions.
        def error(err):
            """ Return False to the callback. """
            callback(False)

        def connected():
            """ Send our message. """
            sock.writeData(message, len(message))

        def bytesWritten(bytes):
            """ If we've written everything, close and return True. """
            if not sock.bytesToWrite():
                sock.close()
                callback(True)

        if callback:
            sock.error.connect(error)
            sock.connect.connect(connected)
            sock.bytesWritten.connect(bytesWritten)

        # Now connect.
        sock.connectToServer(self._app_id)

        if not callback:
            # Do things synchronously.
            connected = sock.waitForConnected(5000)
            if not connected:
                return False

            # Write it.
            sock.writeData(message, len(message))

            # Wait until we've written everything.
            while sock.bytesToWrite():
                success = sock.waitForBytesWritten(5000)
                if not success:
                    sock.close()
                    return False

            sock.close()
            return True
Ejemplo n.º 11
0
 def _createServer(self):
     from PySide.QtNetwork import QLocalServer
     ret = QLocalServer(self.q)
     ret.newConnection.connect(self._onNewConnection)
     return ret