Le chat d'octets

Photo de Gribouille

Créer une application à une seule instance avec PySide6 (Linux)

Nous allons créer une application graphique en utilisant PySide6. Il s'agit d'une application où une seule instance peut être lancée à la fois. Si une instance est déjà en cours, une nouvelle tentative de lancement affichera un message d'erreur et fermera l'application.

Pourquoi limiter une application à une seule instance ?

Une application à instance unique, ou "single-instance application", désigne une application qui ne permet qu'une seule instance (c'est-à-dire une seule exécution) d'être active à la fois sur un système. Il y a plusieurs raisons pour lesquelles certaines applications sont conçues de cette manière :

La bibliothèque fcntl

Pour créer cette application, nous utilisons la bibliothèque fcntl qui permet de manipuler les fichiers et de gérer des opérations de verrouillage et de contrôle sur des fichiers, principalement sous les systèmes Unix (Linux, macOS).
Elle fournit une interface pour interagir avec les appels système de bas niveau, permettant de contrôler les descripteurs de fichiers. Elle est principalement utilisée pour les verrous de fichiers et les configurations de fichiers.

Fonctions principales de fcntl

La bibliothèque fcntl est surtout utilisée pour la gestion des verrous de fichiers et la manipulation des attributs de fichiers. Voici les fonctions les plus courantes :

fcntl.flock()

Cette fonction est utilisée pour verrouiller ou déverrouiller un fichier afin d'éviter les conflits entre plusieurs processus qui pourraient essayer d'accéder ou de modifier le fichier en même temps. L'opération peut être un verrouillage exclusif (exclusif pour un seul processus) ou partagé, et il existe aussi des options pour des verrouillages bloquants ou non-bloquants.

fcntl.flock(file, operation)

Les options pour operation incluent :

fcntl.fcntl()

Cette fonction permet de manipuler des attributs de fichier à un niveau plus bas. Elle est utilisée pour obtenir ou définir des informations comme les options de fichier, la configuration du descripteur de fichier, etc. Elle permet d'utiliser les appels système fcntl() de bas niveau.

fcntl.fcntl(file, cmd, arg=0)

Code du programme

Voici le code qui crée une fenêtre simple avec un message et un bouton qui ferme la fenêtre lorsque l'utilisateur clique dessus.
Il s'agit d'une application où une seule instance peut être lancée à la fois. Si une instance est déjà en cours, une nouvelle tentative de lancement affichera un message d'erreur et fermera l'application.

class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        layout.addWidget(QLabel("Bienvenue dans l'application!"))
        button = QPushButton('Fermer', self)
        button.clicked.connect(self.close)
        layout.addWidget(button)
        self.setLayout(layout)


class SingleApplication(QApplication):
    def __init__(self, sys_argv):
        super().__init__(sys_argv)

        # Crée un fichier de verrouillage unique
        self.lock_file = open("/tmp/my_unique_app.lock", "w+")

        try:
            # Essaye de verrouiller le fichier, si cela échoue, cela signifie qu'une autre instance est déjà en cours
            fcntl.flock(self.lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)
        except IOError:
            print("L'application est déjà en cours d'exécution.")
            sys.exit(0)

    def __del__(self):
        # Déverrouille le fichier de verrouillage lorsque l'application se termine
        fcntl.flock(self.lock_file, fcntl.LOCK_UN)
        self.lock_file.close()


if __name__ == "__main__":
    app = SingleApplication(sys.argv)

    # Créer la fenêtre principale de l'application
    window = MainWindow()
    window.show()

    # Lancer l'application
    sys.exit(app.exec())