Como mostrar uma janela de um aplicativo já ativo ao tentar abrir uma nova instância desse aplicativo

6

Eu sei que a pergunta é um pouco vaga. Vou tentar explicar melhor abaixo:

Meu aplicativo (python / gtk) é principalmente um indicador. Usando este indicador, você pode escolher mostrar / ocultar a janela principal.

Quando tento abrir uma nova instância do aplicativo, verifiquei se o aplicativo já está em execução. Se assim for, seria abortar tentando executar o aplicativo.

Agora eu quero ajustá-lo, então antes de abortar eu quero trazer a janela principal do aplicativo já ativo para o primeiro plano. Mesmo que esta janela não esteja aberta no momento.

Então, acredito que minha pergunta é: como posso obter uma variável / instância (global?) do meu aplicativo já ativo do meu novo aplicativo? (então eu posso trazer minha janela principal para o primeiro plano)

EDITAR:

Acabei de encontrar esse método na API: GtkWindow - set_startup_id ( ) .

Isso diz: Normalmente, o identificador de inicialização é gerenciado automaticamente e você só deve usar essa função em casos especiais, como transferir o foco de outros processos.

Então, isso significa que deve ser possível trazer o foco para uma janela de outro processo. Mas como eu conseguiria esse id? E como eu usaria esse id para trazê-lo para o primeiro plano?

    
por Nick Lemaire 15.07.2012 / 00:19

3 respostas

1

Vamos começar dizendo que existem muitas e muitas maneiras. Você normalmente configura um token / identificador quando o programa é iniciado, para que instâncias posteriores possam procurar a existência desse token.

Eu descreverei uma maneira que usa dbus.

Visão geral:

Ao iniciar um programa, ele pode se registrar na sessão dbus com um nome exclusivo (por exemplo, "org.nicklemaire.myprogram"). Outras instâncias do programa podem verificar se esse ponto de acesso já está registrado e, em caso afirmativo, informar ao programa o que fazer por meio desse ponto de acesso dbus (por exemplo, obter foco, abrir um site, reproduzir uma música). A última parte é provavelmente necessária quando você quer um comportamento semelhante ao "firefox askubuntu.com", que abre esta página em uma nova aba em uma instância já em execução.

Código:

#!/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 __name__ == "__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()

Teste:

Abra um terminal e execute o programa: myprogram.py . Ele não será encerrado porque atualmente queremos que ele seja executado e aguarde até que uma segunda instância seja iniciada.

Agora faça isso: abra outro terminal e execute o programa novamente, desta vez com um argumento adicional myprogram.py askubuntu.com . Deve imprimir: "Outra instância foi executada e notificada." Enquanto no primeiro terminal, você deve obter uma saída semelhante a esta: "obteve o seguinte parâmetro de outra instância: askubuntu.com"

A outra parte da sua pergunta: criar um programa é descrita aqui:

Basicamente, você precisa chamar mywindow.present() no método startup .

    
por xubuntix 04.08.2012 / 19:08
1

Graças a grande resposta do xubuntix , criei um módulo que simplifica:

"""
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 __name__ == '__main__':
    test()

Por favor, consulte a seguinte essência para quaisquer outras revisões no código acima:

por Noam 09.01.2014 / 13:02
0

Não tenho certeza se esse é o ID que você está procurando:

Abra System Monitor , indo para os Aplicativos, pressionando CTRL+ALT+DEL ou digitando no terminal gnome-system-monitor .

Vá para a guia View , na barra superior. Selecione All Processes e dependências. Vá para a guia Edit , na barra superior, e abra Preferences .

Na guia Processes , em Information Fields , selecione ID .

Em seguida, tente encontrar seu programa na lista. Boa sorte!

    
por David M. Sousa 16.07.2012 / 17:36