我知道这个问题有点模糊。我将尝试在下面更好地解释:
我的应用程序 (python/gtk) 主要是一个指示器。使用此指示器,您可以选择显示/隐藏主窗口。
当我尝试打开应用程序的新实例时,我会检查应用程序是否已在运行。如果是,它会中止尝试运行该应用程序。
现在我想调整它,所以在中止之前我希望它将已经活动的应用程序的主窗口带到前台。即使这个窗口目前没有打开。
所以我相信我的问题是:如何从我的新应用程序中获取我已经活动的应用程序的(全局?)变量/实例?(这样我就可以将主窗口带到前台)
编辑:
我刚刚在api中找到了这种方法:GtkWindow-set_startup_id()。
这说:通常,启动标识符是自动管理的,您只应在特殊情况下使用此功能,例如从其他进程转移焦点。
因此,这意味着应该可以将焦点从另一个进程移到窗口。但是我如何获取此 ID?我如何使用此 ID 将其移到前台?
答案1
首先,有很多方法。通常在程序启动时设置一个令牌/标识符,以便后续实例可以查找该令牌的存在。
我将描述一种使用 dbus 的方法。
概述:
启动程序时,它可以在会话 dbus 上以唯一名称(例如“org.nicklemaire.myprogram”)注册自身。程序的其他实例可以检查此类接入点是否已注册,如果已注册,则告诉程序通过此 dbus 接入点执行的操作(例如获取焦点、打开网站、播放歌曲)。最后一部分可能是必要的,因为您想要类似于“firefox askubuntu.com”的行为,它会在已运行的实例的新选项卡中打开此页面。
代码:
#!/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 askubuntu.com
。它应该打印:“另一个实例正在运行并收到通知。”在第一个终端中,您应该获得类似以下内容的输出:“从另一个实例获得以下参数:askubuntu.com”
您的问题的另一部分:提出一个计划,描述如下:https://stackoverflow.com/questions/9054462/how-do-i-raise-a-window-that-is-minimized-or-covered-with-pygobject
基本上,您必须调用mywindow.present()
该startup
方法。
答案2
谢谢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()
对于上述代码的任何进一步修改,请参考以下要点:
答案3
不确定这是否是您要找的 ID:
打开System Monitor
,可以通过进入应用程序、按CTRL+ALT+DEL
或输入终端来打开gnome-system-monitor
。
转到View
顶部栏上的选项卡。选择All Processes
和依赖项。转到Edit
顶部栏上的选项卡,然后打开Preferences
。
在Processes
选项卡上的 下Information Fields
,选择ID
。
然后尝试在列表中找到你的程序。祝你好运!