Как отобразить окно уже активного приложения при попытке открыть новый экземпляр этого приложения

Я знаю, что вопрос немного расплывчатый. Я постараюсь объяснить лучше ниже:

Мое приложение (python/gtk) в основном является индикатором. Используя этот индикатор, вы можете показать / скрыть главное окно.

Когда я пытаюсь открыть новый экземпляр приложения, я сделал это так, чтобы он проверял, запущено ли уже приложение. Если это так, то попытка запустить приложение будет прервана.

Теперь я хочу настроить его, поэтому перед прерыванием я хочу вывести главное окно уже активного приложения на передний план. Даже если это окно не открыто в данный момент.

Поэтому я считаю, что мой вопрос таков: как я могу получить (глобальную?) Переменную / экземпляр моего уже активного приложения из моего нового приложения? (чтобы я мог вывести главное окно на передний план)

РЕДАКТИРОВАТЬ:

Я только что нашел этот метод в API: GtkWindow - set_startup_id ().

Это говорит: как правило, идентификатор запуска управляется автоматически, и вы должны использовать эту функцию только в особых случаях, таких как передача фокуса из других процессов.

Таким образом, это означает, что должна быть возможность перенести фокус на окно из другого процесса. Но как мне получить этот идентификатор? И как бы я использовал этот идентификатор, чтобы вывести его на передний план?

3 ответа

Начнем с того, что есть много способов. Обычно вы устанавливаете токен / идентификатор при запуске программы, чтобы последующие экземпляры могли искать его существование.

Я опишу один способ, который использует dbus.

Обзор:

При запуске программы она может зарегистрироваться в сеансе dbus под уникальным именем (например, "org.nicklemaire.myprogram"). Дальнейшие экземпляры программы могут проверить, зарегистрирована ли уже такая точка доступа, и, если это так, сообщить программе, что делать через эту точку доступа dbus (например, получить фокус, открыть веб-сайт, воспроизвести песню). Последняя часть, вероятно, необходима, если вам нужно поведение, подобное "firefox Ask-ubuntu.ru", которое открывает эту страницу в новой вкладке в уже запущенном экземпляре.

Код:

#!/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()

Тестовое задание:

Откройте терминал и запустите программу: myprogram.py, Он не завершится, потому что в настоящее время мы хотим, чтобы он работал и ждал запуска второго экземпляра.

Теперь сделайте это: откройте другой терминал и снова запустите программу, на этот раз с дополнительным аргументом myprogram.py Ask-ubuntu.ru, Должно быть напечатано: "Другой экземпляр запущен и уведомлен". Находясь в первом терминале, вы должны получить вывод, подобный следующему: "получил следующий параметр из другого экземпляра: Ask-ubuntu.ru"

Другая часть вашего вопроса: поднятие программы описано здесь: https://stackoverflow.com/questions/9054462/how-do-i-raise-a-window-that-is-minimized-or-covered-with-pygobject

В основном, вы должны позвонить mywindow.present() в startup метод.

Благодаря отличному ответу xubuntix, я создал модуль, который делает его простым:

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

Пожалуйста, обратитесь к следующему пункту для любых дальнейших изменений в коде выше:

Не уверен, что это ID, который вы ищете:

открыто System MonitorЛибо перейдя в Приложения, нажав CTRL+ALT+DEL или набрав в терминале gnome-system-monitor,

Идти к View вкладка, на верхней панели. Выбрать All Processes и зависимости. Идти к Edit на верхней панели и откройте Preferences,

На Processes вкладка под Information Fields, Выбрать ID,

Затем попробуйте найти свою программу в списке. Удачи!

Другие вопросы по тегам