web-dev-qa-db-fra.com

Comment afficher une fenêtre d'une application déjà active lorsque vous essayez d'ouvrir une nouvelle instance de cette application

Je sais que la question est un peu vague. Je vais essayer d'expliquer mieux ci-dessous:

Mon application (python/gtk) est principalement un indicateur. En utilisant cet indicateur, vous pouvez choisir d’afficher/masquer la fenêtre principale.

Lorsque j'essaie d'ouvrir une nouvelle instance de l'application, je l'ai créée afin de vérifier si l'application est déjà en cours d'exécution. Si tel est le cas, il essaierait de lancer l'application.

Maintenant, je veux l'ajuster. Par conséquent, avant d'abandonner, je veux qu'il fasse apparaître la fenêtre principale de l'application déjà active au premier plan. Même si cette fenêtre n'est pas ouverte pour le moment.

Je pense donc que ma question est la suivante: comment puis-je obtenir une variable/instance (globale?) De mon application déjà active à partir de ma nouvelle application? (je peux donc amener ma fenêtre principale au premier plan)

MODIFIER:

Je viens de trouver cette méthode dans l'api: GtkWindow - set_startup_id () .

Cela dit: Normalement, l'identifiant de démarrage est géré automatiquement et vous ne devez utiliser cette fonction que dans des cas particuliers tels que le transfert du focus depuis d'autres processus.

Cela signifie donc qu'il devrait être possible de mettre en évidence une fenêtre provenant d'un autre processus. Mais comment pourrais-je obtenir cet identifiant? Et comment pourrais-je utiliser cet identifiant pour l'amener au premier plan?

6
Nick Lemaire

Grâce à la bonne réponse de xubuntix , j'ai créé un module qui simplifie les choses:

"""
Allow an application to activate a running instance of itself instead of
starting another instance.
"""

import sys

import gtk
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop

def _get_path(app_id):
    return '/' + app_id.replace('.', '/')

def listen_for_activation(app_id, window):
    """
    Listen for 'activate' events. If one is sent, activate 'window'.
    """
    class MyDBUSService(dbus.service.Object):                                                                                                       
        def __init__(self, window):
            self.window = window

            bus_name = dbus.service.BusName(app_id, bus=dbus.SessionBus())                                                     
            dbus.service.Object.__init__(self, bus_name, _get_path(app_id))

        @dbus.service.method(app_id)                                                                         
        def activate(self):
            print "The process was activated by another instance."
            self.window.present()

    DBusGMainLoop(set_as_default=True)
    _myservice = MyDBUSService(window)

def activate_if_already_running(app_id):
    """
    Activate the existing window if it's already running. Return True if found
    an existing window, and False otherwise.
    """
    bus = dbus.SessionBus()
    try:
        programinstance = bus.get_object(app_id, _get_path(app_id))
        activate = programinstance.get_dbus_method('activate', app_id)
    except dbus.exceptions.DBusException:
        return False
    else:
        print "A running process was found. Activating it."
        activate()
        return True
    finally:
        bus.close()

def test():
    APP_ID = 'com.example.myapp'

    activated = activate_if_already_running(APP_ID)
    if activated:
        sys.exit(0)

    w = gtk.Window()
    b = gtk.Button("Hello!")
    b.set_size_request(200, 200)
    w.add(b)
    w.connect('delete-event', gtk.main_quit)
    w.show_all()

    listen_for_activation(APP_ID, w)

    gtk.main()

if __== '__main__':
    test()

Veuillez vous reporter à l’essentiel suivant pour toute révision ultérieure dans le code ci-dessus:

1
Noam

Commençons par dire qu'il y a beaucoup de façons. Vous configurez normalement un jeton/identificateur au démarrage du programme afin que des instances ultérieures puissent rechercher l'existence de ce jeton.

Je vais décrire un moyen qui utilise dbus.

Vue d'ensemble:

Lors du démarrage d’un programme, il peut s’inscrire lui-même sur la session dbus sous un nom unique (par exemple, "org.nicklemaire.myprogram"). D'autres instances du programme peuvent vérifier si un tel point d'accès est déjà enregistré et, le cas échéant, indiquer au programme ce qu'il doit faire via ce point d'accès dbus (par exemple, sélectionnez le focus, ouvrez un site Web, jouez une chanson). La dernière partie est probablement nécessaire lorsque vous souhaitez un comportement similaire à "firefox askubuntu.com", qui ouvre cette page dans un nouvel onglet dans une instance en cours d'exécution.

Code:

#!/usr/bin/env python                                                                                                                           
import sys                                                                                                                                      
import gtk                                                                                                                                      
import dbus                                                                                                                                     
import dbus.service                                                                                                                             
from dbus.mainloop.glib import DBusGMainLoop                                                                                                    
from multiprocessing import Process                                                                                                             

class MyDBUSService(dbus.service.Object):                                                                                                       
    def __init__(self):                                                                                                                         
        bus_name = dbus.service.BusName('org.nicklemaire.myprogram', bus=dbus.SessionBus())                                                     
        dbus.service.Object.__init__(self, bus_name, '/org/nicklemaire/myprogram')                                                              

    @dbus.service.method('org.nicklemaire.myprogram', in_signature='s')                                                                         
    def startup(self, arg):                                                                                                                     
        print "got the following parameter from another instance:", arg                                                                         

def call_instance():                                                                                                                            
    try:                                                                                                                                        
        bus = dbus.SessionBus()                                                                                                                 
        programinstance = bus.get_object('org.nicklemaire.myprogram',  '/org/nicklemaire/myprogram')                                            
        bus = dbus.SessionBus()                                                                                                                 
        programinstance = bus.get_object('org.nicklemaire.myprogram',  '/org/nicklemaire/myprogram')                                            
        startup = programinstance.get_dbus_method('startup', 'org.nicklemaire.myprogram')                                                       
        try:                                                                                                                                    
            arg = sys.argv[1]                                                                                                                   
        except IndexError:                                                                                                                      
            arg = ""                                                                                                                            
        startup(arg)                                                                                                                            
        print "Another instance was running and notified."                                                                                      
    except dbus.exceptions.DBusException:                                                                                                       
        exit(-1) # process had an error                                                                                                         

if __== "__main__":                                                                                                                      
    p = Process(target=call_instance)                                                                                                           
    p.start() 
    p.join()                                                                                                                                    
    if p.exitcode > 0: # process had an error                                                                                                   
        DBusGMainLoop(set_as_default=True)                                                                                                      
        myservice = MyDBUSService()                                                                                                             
        gtk.main()

Test:

Ouvrez un terminal et lancez le programme: myprogram.py. Il ne se terminera pas car nous souhaitons actuellement qu'il soit exécuté et en attente du démarrage d'une deuxième instance.

Maintenant, faites ceci: ouvrez un autre terminal et exécutez le programme à nouveau, cette fois avec un argument supplémentaire myprogram.py askubuntu.com. Il devrait imprimer: "Une autre instance était en cours d'exécution et notifiée." Dans le premier terminal, vous devriez obtenir une sortie semblable à celle-ci: "a obtenu le paramètre suivant à partir d'une autre instance: askubuntu.com"

L’autre partie de votre question: la création d’un programme est décrite ci-après: https://stackoverflow.com/questions/9054462/how-do-i-raise-a-window-that-is-minimized-or- couvert-avec-pygobject

En gros, vous devez appeler mywindow.present() dans la méthode startup.

1
xubuntix

Pas sûr que ce soit l'ID que vous recherchez:

Ouvrez System Monitor, soit en accédant aux applications, en appuyant sur CTRL+ALT+DEL, soit en saisissant le terminal gnome-system-monitor.

Accédez à l'onglet View, dans la barre supérieure. Sélectionnez All Processes et les dépendances. Allez sur l'onglet Edit, dans la barre supérieure, et ouvrez Preferences.

Sur l'onglet Processes, sous Information Fields, sélectionnez ID.

Ensuite, essayez de trouver votre programme dans la liste. Bonne chance!

0
David M. Sousa