使用Python在App Indicators中使用Gtk.Widgets

2010年,Stefano Palazzo提出了一个相关问题将任意的gtk.Widget放入appindicator.Indicator中,类似的问题也在StackOverflow上被提出。在这两种情况下,共识是Ubuntu的应用指示器功能有限。正如Michael Ekstrand所说:

应用指示器菜单支持基于D-Bus菜单,它们在支持方面有限 - 它们只支持基本的菜单功能,而不支持更多的奇特事物,比如任意的小部件。

然而,与之相矛盾的是我们在今天的蓝牙指示器中看到的情况,即在2016年:它使用了切换开关。

enter image description here

从13.04版本开始,我们也可以观察到Ubuntu One指示器的相同情况。

enter image description here

显然有一种方法。我已经研究了指示器蓝牙的源代码,但它是用Vala编写的。然而,我主要使用Python进行工作,学习Vala只是为了重写我已经存在的所有指示器,这有点太多工作了。
所以问题的核心是:如何使用Python使用Gtk.Widgets,或者至少像蓝牙指示器中那样使用切换开关?
注意:我愿意对这个问题提供悬赏,以奖励一个能够提供一个在Python中工作的示例的答案。其他语言不被接受。

6应用程序指示器受限,甚至不支持即时图标(它只从文件系统加载图像文件)。你提到的那些指示器是系统指示器(蓝牙、Ubuntu One、声音、电源等)。它们是不同的,也不使用libappindicator。我已经发布了一些帖子,可能有助于澄清这种区别。我已经成功使用C语言创建了一个系统指示器,但在Python中我仍然遇到困难。 - user.dz
2有没有办法吸引Ubuntu核心开发者对这个问题的注意? - don.joey
@don.joey 我觉得没有,Ubuntu核心开发人员不是合适的人来问。菜单是通过DBus Menu API传递的,这意味着那个API的开发人员更适合提问。 - Sergiy Kolodyazhnyy
1至少test = Gtk.CheckMenuItem("Monkey")可以添加一个复选框,但应该还有更多的方法。虽然这个方法可以工作,但这个方法Gtk.CheckMenuItemToggled("Monkey")却不能工作。我相信它无论如何都能工作。请参考:https://developer.gnome.org/gtk3/stable/GtkCheckMenuItem.html - Jacob Vlijm
1@JacobVlijm 是的,添加任何单个菜单项都可以,也可以添加一个 Gtk.Box 并将 Gtk.Label 添加到该盒子中,但不能添加其他内容(它会显示该小部件只能包含一个项目)。 - Sergiy Kolodyazhnyy
是的,尝试添加一个框,可以正常工作,但是“正常”的 GUI 小部件被拒绝。它还应该支持带有切换按钮的菜单项。不是 GUI 版本,而是菜单版本。 - Jacob Vlijm
是的,检查菜单项、单选菜单项和图像菜单项 - 这三个都可以工作。其他小部件不行。我找到了一个AskUbuntu的答案,OP联系了DBusMenu的开发人员,他们说计划添加对其他小部件的支持。那是在2011年的事情了,所以我希望有所改变。 - Sergiy Kolodyazhnyy
1Gtk.ImageMenuItem 已被弃用并不鼓励使用。请参考:https://developer.gnome.org/gtkmm/stable/deprecated.html - Jacob Vlijm
嗨Serg,这不是一个答案,但是从多个来源来看,Gtk菜单的政策更倾向于拥有一个“纯净”的、朴素的菜单,没有小部件,没有图标。我们过去所拥有的(少量)选项要么消失了,要么被弃用,要么受到其他限制。我不相信我们会找到一个可行的答案。将来的可能性更小。 - Jacob Vlijm
请注意在描述Unity7或Unity8时要具体说明,因为它们在支持/公开小部件功能方面存在差异。 - Kristopher Ives
@SergiyKolodyazhnyy,我刚刚得知有人分叉了我的C系统指示器模板,并创建了一个带有滑块的系统指示器,与Canonical指示器相同(他们使用了一些DBus技巧)。这是该存储库:https://github.com/okaresz/ScreenToolsSysIndicator,请检查代码中的`g_menu_item_set_attribute(brightnessItem, "x-canonical-type", "s", "com.canonical.unity.slider")`,这是他添加滑块项目的地方。据我所了解,Canonical以同样的方式创建了其他组件,但它们仅在内部使用,没有公共API或文档。 - user.dz
1个回答

这个问题存在的原因是,虽然AppIndicators使得创建一个指示菜单变得容易,但它们也妨碍了创建菜单。让我们来看一下使用AppIndicator和使用GLib Menus(就像蓝牙代码所做的那样)的示例Python代码之间的区别。
首先,你被要求创建一个gtk.Menu,这些是使用Gtk.Action的旧式Gtk菜单对象,现在已经被弃用。在set_menu(...)过程中,AppIndicator会从你那里获取gtk.Menu对象,并解析它,将找到的每个菜单推送到使用libdbusmenu创建的指示服务上。这个解析过程意味着任何不受AppIndicator支持的内容都会被过滤掉,无论你做什么。
接下来,让我们来看一下蓝牙菜单。它是使用Gio.Menu对象创建的,这些是使用GAction系统的新式Gnome菜单。然后,它注册了自己的服务,而没有使用AppIndicatorlibdbusmenu,并使用自定义的x-canonical-type属性设置它,以创建传递给libido进行解析的切换小部件。
这整个练习都很糟糕,因为这都是Canonical自己的Unity定制。所以一旦Unity消失了,就没有应用程序指示器了。

继续关注这个(很棒的)答案,Unity现在被Gnome取代了,但是AppIndicator3在Gnome中确实可以工作(虽然它是一个名为AyatanaAppIndicator3的新库,看起来是一个可替换的版本)。 - Frug