Как отобразить окно уже активного приложения при попытке открыть новый экземпляр этого приложения
Я знаю, что вопрос немного расплывчатый. Я постараюсь объяснить лучше ниже:
Мое приложение (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
,
Затем попробуйте найти свою программу в списке. Удачи!