Tales of a GeekTrotter Binary Logbook

10May/110

Python Qt4 recipe: QSingleApplication (PySide)

Thanks to Renato Filho who helped me in this thread on the Qt Forums, I made a simple QSingleApplication class for PySide that allows you to be sure your program will be started only once.

In addition to start the application only once, we can send the arguments of the later calls of your program to the first (and only remaining) instance.

The following video summarizes the features:

The idea is to use the QLocalServer / QLocalSocket classes to perform the check and communication between the instances.

First, we create a socket and try to connect to the server, registered with the application name.

        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)

If the connection works, it means a server has already been registered, so the application has already been started and we try to connect to that existing application.
If we the new call has been made with arguments, we send them to the already running application (the first one only in this example, adapt to your needs for all).
If the new call has been made without any arguments, we notice the user that the program is already running and we quit.

    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)

If the connection fails, then it means this is the first instance of the application so we start the application and register a server listening to future applications.

    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."))

You can retrieve the complete source code at Gitorious: qSingleApplication.py