AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / ubuntu / 问题 / 786831
Accepted
user.dz
user.dz
Asked: 2016-06-15 03:21:52 +0800 CST2016-06-15 03:21:52 +0800 CST 2016-06-15 03:21:52 +0800 CST

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

  • 772

背景:

  • 这不适用于application-indicators而是system-indicators。

    指标布局

    图片来自:https ://wiki.ubuntu.com/DesktopExperienceTeam/ApplicationIndicators

  • 目标是在 Greeter/Lock/Ubiquity 屏幕中显示指标系统监视器。有一个解决方法:

    如何将 indicator-sysmonitor 作为登录屏幕上的默认指标

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

    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
    

    local.sneetsher.indicator.test.service

    [D-BUS Service]
    Name=local.sneetsher.indicator.test
    Exec=/usr/lib/indicator-test/indicator-test-service
    

    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']
    

问题:

我期待原因,我没有像_header在原始 C 代码中那样创建菜单结构或其元(伪项,如 )。

任何人都可以用 C 语言将此系统指标代码移植到 Python 吗?

unity
  • 2 2 个回答
  • 3621 Views

2 个回答

  • Voted
  1. Best Answer
    Marto
    2020-11-14T04:35:15+08:002020-11-14T04:35:15+08:00

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

    • github.com/marto-ales/systemindicator

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

    感谢您提供有用的信息!


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

    #!/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)
    
    • 4
  2. DCM
    2020-11-20T17:51:44+08:002020-11-20T17:51:44+08:00

    系统指标服务

    嗯,它真的比我预期的要简单。它没有特定的 API。因为它只是一个 GSimpleActionGroup & 并通过 DBus 导出了相应的 GMenu,所以使用放入的同名声明文件告知 Unity 它们的存在/usr/share/unity/indicators/。不需要任何其他库。

    这是一个非常小的 C 语言示例:

    tests/indicator-test-service.c从libindicator源获取副本

    apt-get source libindicator
    cp libindicator-*/tests/indicator-test-service.c .
    cp libindicator-*/tests/com.canonical.indicator.test*
    

    . 指标测试服务.c没有变化

    **#include <gio/gio.h>
    
    typedef struct
    {
      GSimpleActionGroup *actions;
      GMenu *menu;
    
      guint actions_export_id;
      guint menu_export_id;
    } IndicatorTestService;
    
    static void
    bus_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)
    {
      IndicatorTestService *indicator = user_data;
      GError *error = NULL;
    
      indicator->actions_export_id = g_dbus_connection_export_action_group (connection,
                                                                            "/com/canonical/indicator/test",
                                                                            G_ACTION_GROUP (indicator->actions),
                                                                            &error);
      if (indicator->actions_export_id == 0)
        {
          g_warning ("cannot export action group: %s", error->message);
          g_error_free (error);
          return;
        }
    
      indicator->menu_export_id = g_dbus_connection_export_menu_model (connection,
                                                                       "/com/canonical/indicator/test/desktop",
                                                                       G_MENU_MODEL (indicator->menu),
                                                                       &error);
      if (indicator->menu_export_id == 0)
        {
          g_warning ("cannot export menu: %s", error->message);
          g_error_free (error);
          return;
        }
    }
    
    static void
    name_lost (GDBusConnection *connection,
               const gchar     *name,
               gpointer         user_data)
    {
      IndicatorTestService *indicator = user_data;
    
      if (indicator->actions_export_id)
        g_dbus_connection_unexport_action_group (connection, indicator->actions_export_id);
    
      if (indicator->menu_export_id)
        g_dbus_connection_unexport_menu_model (connection, indicator->menu_export_id);
    }
    
    static void
    activate_show (GSimpleAction *action,
                   GVariant      *parameter,
                   gpointer       user_data)
    {
      g_message ("showing");
    }
    
    int
    main (int argc, char **argv)
    {
      IndicatorTestService indicator = { 0 };
      GMenuItem *item;
      GMenu *submenu;
      GActionEntry entries[] = {
        { "_header", NULL, NULL, "{'label': <'Test'>,"
                                 " 'icon': <'indicator-test'>,"
                                 " 'accessible-desc': <'Test indicator'> }", NULL },
        { "show", activate_show, NULL, NULL, NULL }
      };
      GMainLoop *loop;
    
      indicator.actions = g_simple_action_group_new ();
      g_simple_action_group_add_entries (indicator.actions, entries, G_N_ELEMENTS (entries), NULL);
    
      submenu = g_menu_new ();
      g_menu_append (submenu, "Show", "indicator.show");
      item = g_menu_item_new (NULL, "indicator._header");
      g_menu_item_set_attribute (item, "x-canonical-type", "s", "com.canonical.indicator.root");
      g_menu_item_set_submenu (item, G_MENU_MODEL (submenu));
      indicator.menu = g_menu_new ();
      g_menu_append_item (indicator.menu, item);
    
      g_bus_own_name (G_BUS_TYPE_SESSION,
                      "com.canonical.indicator.test",
                      G_BUS_NAME_OWNER_FLAGS_NONE,
                      bus_acquired,
                      NULL,
                      name_lost,
                      &indicator,
                      NULL);
    
      loop = g_main_loop_new (NULL, FALSE);
      g_main_loop_run (loop);
    
      g_object_unref (submenu);
      g_object_unref (item);
      g_object_unref (indicator.actions);
      g_object_unref (indicator.menu);
      g_object_unref (loop);
    
      return 0;
    }**
    

    com.canonical.indicator.test修改为添加锁定和欢迎模式

    [Indicator Service]
    Name=indicator-test
    ObjectPath=/com/canonical/indicator/test
    
    [desktop]
    ObjectPath=/com/canonical/indicator/test/desktop
    
    [desktop_greeter]
    ObjectPath=/com/canonical/indicator/test/desktop
    
    [desktop_lockscreen]
    ObjectPath=/com/canonical/indicator/test/desktop
    

    com.canonical.indicator.test.service从文件名中删除 .in 后缀并更改可执行路径

    [D-BUS Service]
    Name=com.canonical.indicator.test
    Exec=/usr/lib/x86_64-linux-gnu/indicator-test/indicator-test-service
    

    编译它

    gcc -o indicator-test-service indicator-test-service.c pkg-config --cflags --libs gtk+-3.0
    

    手动安装

    sudo su
    mkdir /usr/lib/x86_64-linux-gnu/indicator-test/
    cp indicator-test-service /usr/lib/x86_64-linux-gnu/indicator-test/
    cp com.canonical.indicator.test /usr/share/unity/indicators/
    cp com.canonical.indicator.test.service /usr/share/dbus-1/services/
    

    Greeter 的配置,覆盖默认指标列表

    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', 'com.canonical.indicator.test', 'application']
    

    安装

    cp 90_unity-greeter.gschema.override /usr/share/glib-2.0/schemas/
    glib-compile-schemas /usr/share/glib-2.0/schemas/
    

    测试

    sudo service lightdm restart
    

    如果您希望用户能够随时关闭应用程序,请注意DBus 服务很麻烦。最好使用自动启动,就像默认指标一样。

    我在这里上传了准备好的文件:

    https://github.com/sneetsher/mysystemindicator_minimum

    以及此处的修改副本:

    https://github.com/sneetsher/mysystemindicator

    我尝试过不同模式的不同菜单。它可以快速安装和测试。

    这似乎太简单了,可以很容易地移植到任何其他支持 GIO Gnome lib(包括 DBus)的语言。由于我正在寻找python,我可能会在稍后添加它。

    参考: libindicator README:指标服务文件格式https://bazaar.launchpad.net/~indicator-applet-developers/libindicator/trunk.14.04/view/head:/README

    • 0

相关问题

  • 如何将 Web 应用程序放入 Unity Launcher?

  • Ubuntu 上网本 10.10 中没有 Alt+F2?

  • Unity 中的 gnome-do 样式键盘快捷键

  • 在哪里提交 Unity 的错误/愿望清单?

  • Unity 启动器——它可以作为单独的包提供吗?

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    如何运行 .sh 脚本?

    • 16 个回答
  • Marko Smith

    如何安装 .tar.gz(或 .tar.bz2)文件?

    • 14 个回答
  • Marko Smith

    如何列出所有已安装的软件包

    • 24 个回答
  • Marko Smith

    无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗?

    • 25 个回答
  • Martin Hope
    Flimm 如何在没有 sudo 的情况下使用 docker? 2014-06-07 00:17:43 +0800 CST
  • Martin Hope
    Ivan 如何列出所有已安装的软件包 2010-12-17 18:08:49 +0800 CST
  • Martin Hope
    La Ode Adam Saputra 无法锁定管理目录 (/var/lib/dpkg/) 是另一个进程在使用它吗? 2010-11-30 18:12:48 +0800 CST
  • Martin Hope
    David Barry 如何从命令行确定目录(文件夹)的总大小? 2010-08-06 10:20:23 +0800 CST
  • Martin Hope
    jfoucher “以下软件包已被保留:”为什么以及如何解决? 2010-08-01 13:59:22 +0800 CST
  • Martin Hope
    David Ashford 如何删除 PPA? 2010-07-30 01:09:42 +0800 CST

热门标签

10.10 10.04 gnome networking server command-line package-management software-recommendation sound xorg

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve