如何在 Python 中编写 Unity 系统指标?

use*_*.dz 82 indicator python unity dbus c

背景:

C 原始代码:(工作正常)

  • 我已经在 C 语言中工作了,请参阅我的另一个问题:

    如何为 Unity 开发系统指标?

    但是,indicator-sysmonitor与许多其他应用程序指标一样,它已经是用 Python 开发的。我不喜欢这样的想法:如果开发人员想在欢迎/锁定/无处不在的屏幕中显示指示器,他们必须将他们的项目移植到 C 或编写 Python-C 代理。相反,让 indicator-sysmonitor 直接从 python 创建一个系统指示器将是最好的解决方案(没有变通方法,它将是当前使用 appindicator 的所有 python 项目的通用解决方案)。

Python 代码:(我尝试将 c 代码移植到 python 失败)

  • 我正在努力将它移植到 Python 中。这是我当前的代码,它不起作用。它确实为菜单和操作创建了 DBus 对象。它列在 XFCE 指标插件中。但没有显示在面板上。

    /usr/lib/indicator-test/indicator-test-service

    #!/usr/bin/python2
    
    import os
    import sys
    
    import gi
    from gi.repository import Gio, GLib
    
    APPLICATION_ID = 'local.sneetsher.indicator.test'
    DBUS_MENU_PATH = '/local/sneetsher/indicator/test/desktop'
    DBUS_ACTION_PATH = '/local/sneetsher/indicator/test'
    
    def callback():
        print ok
    
    def quit_callback(notification, loop):
        global connection
        global exported_action_group_id
        global exported_menu_model_id
    
        connection.unexport_action_group (exported_action_group_id)
        connection.unexport_menu_model (exported_menu_model_id)
    
        loop.quit()
    
    def cancel (notification, action, data):
        if action == "cancel":
            print "Cancel"
        else:
            print "That should not have happened (cancel)!"
    
    def bus_acquired(bus, name):
        # menu
        submenu = Gio.Menu()
        submenu.append("Show", "show")
        item = Gio.MenuItem.new(None, "_header")
        item.set_attribute([("x-canonical-type","s","com.canonical.indicator.root")])
        item.set_submenu(submenu)
        menu = Gio.Menu()
        menu.append_item (item)
    
        actions = Gio.SimpleActionGroup.new()
        action1 = Gio.SimpleAction.new("_header", None)
        actions.insert(action1)
        action2 = Gio.SimpleAction.new('show', None)
        actions.insert(action2)
        action2.connect("activate",callback)
    
        global connection
        connection = bus
    
        global exported_action_group_id
        exported_action_group_id = connection.export_action_group(DBUS_ACTION_PATH, actions)
    
        global exported_menu_model_id
        exported_menu_model_id = connection.export_menu_model(DBUS_MENU_PATH, menu)
    
    def setup ():
        #bus connection
        Gio.bus_own_name(Gio.BusType.SESSION, APPLICATION_ID, 0, bus_acquired, None, None)
    
    if __name__ == '__main__':
    
        connection = None
        exported_menu_model_id = 0
        exported_action_group_id = 0
        password = ""
    
        loop = GLib.MainLoop()
        setup ()
    
        loop.run()
    
    Run Code Online (Sandbox Code Playgroud)

    local.sneetsher.indicator.test

    [Indicator Service]
    Name=indicator-test
    ObjectPath=/local/sneetsher/indicator/test
    
    [desktop]
    ObjectPath=/local/sneetsher/indicator/test/desktop
    
    [desktop_greeter]
    ObjectPath=/local/sneetsher/indicator/test/desktop
    
    [desktop_lockscreen]
    ObjectPath=/local/sneetsher/indicator/test/desktop
    
    Run Code Online (Sandbox Code Playgroud)

    local.sneetsher.indicator.test.service

    [D-BUS Service]
    Name=local.sneetsher.indicator.test
    Exec=/usr/lib/indicator-test/indicator-test-service
    
    Run Code Online (Sandbox Code Playgroud)

    90_unity-greeter.gschema.override

    [com.canonical.unity-greeter]
    indicators=['ug-accessibility', 'com.canonical.indicator.keyboard', 'com.canonical.indicator.session', 'com.canonical.indicator.datetime', 'com.canonical.indicator.power', 'com.canonical.indicator.sound', 'local.sneetsher.indicator.test', 'application']
    
    Run Code Online (Sandbox Code Playgroud)

题:

我想知道为什么,我没有像_header原始 C 代码中那样创建菜单结构或其元(如 的伪项目)。

任何人都可以将这个系统指标代码的 C 语言移植到 Python 中吗?

小智 4

我刚刚上传了一个从@user.dz C example移植的原始“工作”Python 示例。这是源代码存储库:

我会随时更新它,但欢迎任何贡献。

感谢您提供有用的信息!


移植了主脚本的源代码。注意:这是初始副本,因为链接将来可能会损坏。有关完整包和最新更新,请点击上面的链接。

#!/usr/bin/python3
import sys
import os
import logging
import logging.handlers
logger = logging.getLogger('LoginHelper')
logger.setLevel(logging.DEBUG)
handler = logging.handlers.SysLogHandler(address = '/dev/log')
logger.addHandler(handler)
logger.debug("Login-Helper: Start")
os.environ["DISPLAY"] = ":0"

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gio
from gi.repository import GLib


class LoginHelperIndicator():

  def __init__(self, dbus_name, dbus_path):
    self.dbus_name = dbus_name
    self.dbus_path = dbus_path
    self.actions = Gio.SimpleActionGroup()
    self.menu = Gio.Menu()
    self.actions_export_id = 0
    self.menu_export_id = 0



  def activate_about (self, action, parameter):
    # gtk_show_about_dialog(NULL,
    #                       "program-name", PROJECT_NAME,
    #                       "title", "About " PROJECT_NAME,
    #                       "version", PROJECT_VERSION_MAJOR "." PROJECT_VERSION_MINOR,
    #                       "license_type", GTK_LICENSE_GPL_3_0,
    #                       "wrap_license", TRUE,
    #                       "website", "https://github.com/sneetsher/mysystemindicator",
    #                       "website_label", "https://github.com/sneetsher/mysystemindicator",
    #                       "logo_icon_name", "indicator-" SHORT_NAME,
    #                       NULL);
    # g_message ("showing about dialog");
    pass

  def activate_private (self, action, parameter):
    #g_message ("clicked private menu entry");
    pass

  def activate_exit (self, action, parameter):
    #g_message ("exit the program");
    Gtk.main_quit()

  def on_bus_acquired (self, connection, name):
    logger.debug ('Bus acquired: ' + str(connection))
    error = None
    item = Gio.MenuItem()
    submenu = Gio.Menu()

    action_state = GLib.Variant("a{sv}", {
      'label': GLib.Variant("s", "Login-helper"),
      'icon':  GLib.Variant("s", "indicator-loginhelper"),
      'accessible-desc': GLib.Variant("s", "Login Helper indicator")
    })
    self.actions.add_action(Gio.SimpleAction.new_stateful("_header", None, action_state))
    about_action = Gio.SimpleAction.new("about", None)
    about_action.connect("activate", self.activate_about)
    self.actions.add_action(about_action)
    private_action = Gio.SimpleAction.new("private", None)
    private_action.connect("activate", self.activate_private)
    self.actions.add_action(private_action)
    exit_action = Gio.SimpleAction.new("exit", None)
    exit_action.connect("activate", self.activate_exit)
    self.actions.add_action(exit_action)

    submenu.append("About", "indicator.about")
    submenu.append("Exit", "indicator.exit")
    item = Gio.MenuItem().new(None, "indicator._header")
    item.set_attribute_value("x-canonical-type", GLib.Variant("s", "com.canonical.indicator.root"))
    item.set_submenu(submenu)

    self.menu = Gio.Menu.new()
    self.menu.append_item(item)

    self.actions_export_id = connection.export_action_group(self.dbus_path, self.actions)
    if self.actions_export_id == 0:
      #g_warning ("cannot export action group: %s", error->message);
      #g_error_free (error);
      return

    self.menu_export_id = connection.export_menu_model(self.dbus_path + "/greeter", self.menu)
    if self.menu_export_id == 0:
      #g_warning ("cannot export menu: %s", error->message);
      #g_error_free (error);
      return


  def on_name_lost (self, connection, name):
    if self.actions_export_id:
      connection.unexport_action_group(self.actions_export_id)

    if (self.menu_export_id):
      connection.unexport_menu_model(self.menu_export_id)


if __name__ == '__main__':

  logger.debug('Login-Helper: Initializing Login Helper Indicator')

  res_gtk = Gtk.init(sys.argv)
  indicator = LoginHelperIndicator('com.canonical.indicator.loginhelper', '/com/canonical/indicator/loginhelper')

  logger.debug ('Login-Helper: Res_gtk: ' + str(res_gtk))
  res_own = Gio.bus_own_name(Gio.BusType.SESSION,
                indicator.dbus_name,
                Gio.BusNameOwnerFlags.NONE,
                indicator.on_bus_acquired,
                None,
                indicator.on_name_lost)
  logger.debug ('Login-Helper: Res_own: ' + str(res_own))

  Gtk.main()

  exit(0)
Run Code Online (Sandbox Code Playgroud)