Ubuntu – submenu items in Unity launcher dynamic quicklist

dbuslauncherpythonunity

How to make a submenu in a dynamic quicklist (of dbusMenuItems) in python?

The official documentation is very scarce:
https://wiki.ubuntu.com/Unity/LauncherAPI

Here is my minimal coding example: dbus_snippet.py

    #!/usr/bin/env python
    from gi.repository import Unity, Gio, GObject, Dbusmenu
    import os
    import subprocess

    launchers = []
    qlList = []

    #(not all references are links due to askubuntu's reputation-system)
    #askubuntu "how-to-add-checkbox-or-radio-buttons-to-a-unity-quicklist"
    #https://lazka.github.io/pgi-docs/Dbusmenu-0.4/classes/Menuitem.html#Dbusmenu.Menuitem

    #(project that this research may go into)
    #(github thirschbuechler/ubuntu-recentquicklists)


    def check_item_activated_callback (menuitem, a, b):#for the submenu
        if menuitem.property_get_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE) == Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED:
           menuitem.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_UNCHECKED)
        else:
           menuitem.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED)

    def check_item_activated(menuitem, a, arg):#main menu item
        process = subprocess.Popen("gedit ",shell=True)

    def createItem(name, arg, qlnummer):
        item = Dbusmenu.Menuitem.new()
        item.property_set (Dbusmenu.MENUITEM_PROP_LABEL, name)
        item.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, True)
        item.connect("item-activated", check_item_activated,arg)
        check1 = Dbusmenu.Menuitem.new ()
        check1.property_set (Dbusmenu.MENUITEM_PROP_LABEL, "Checkbox")
        check1.property_set (Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE, Dbusmenu.MENUITEM_TOGGLE_CHECK)
        check1.property_set_int (Dbusmenu.MENUITEM_PROP_TOGGLE_STATE, Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED)
        check1.property_set_bool (Dbusmenu.MENUITEM_PROP_VISIBLE, True)
        check1.property_set (Dbusmenu.MENUITEM_PROP_CHILD_DISPLAY, Dbusmenu.MENUITEM_CHILD_DISPLAY_SUBMENU)
        #check1.property_set (Dbusmenu.MENUITEM_PROP_CHILD_DISPLAY,  'children-display')
        #https://lazka.github.io/pgi-docs/Dbusmenu-0.4/constants.html#Dbusmenu.MENUITEM_CHILD_DISPLAY_SUBMENU

        check1.connect (Dbusmenu.MENUITEM_SIGNAL_ITEM_ACTIVATED, check_item_activated_callback, None)
        item.child_append(check1)   

        qlList[qlnummer].child_append(item) 



    def update(a=None):
        #delete old ones 
        for i in range(len(qlList)):
            for c in qlList[i].get_children():
                qlList[i].child_delete(c)

    def main():

        launchers.append(Unity.LauncherEntry.get_for_desktop_id ("nautilus.desktop"))
        launchers.append(Unity.LauncherEntry.get_for_desktop_id ("nemo.desktop"))


        for i in range(len(launchers)):
            qli = Dbusmenu.Menuitem.new()
            qlList.append(qli)


        update()

        for i in range(len(launchers)):
            createItem("item1","arg1",i)
            launchers[i].set_property("quicklist", qlList[i])

        loop = GObject.MainLoop()

        loop.run()

    main()

What do I mean by submenu (made in gimp):
enter image description here

Why do I think this is even possible?
An option called Dbusmenu.MENUITEM_PROP_CHILD_DISPLAY, reads "have the subitems displayed as a submenu" sounds awfully close to what I want to do, but I've failed to archive that.
The above snippet adds a dbus-item to another one, and sets the submenu-property (on the Nemo/Nautilus launcher)

(Bonus: I haven't found anything to make check_item_activated distinguish rightclick, leftclick and middle-mouse-button, but prove me wrong)

Best Answer

I don't know how to do this with dbus but ....

You can just do this by editing .desktop files , the changes are automatically picked up. It should be simple enough to write a class to write or edit .desktop files in ~/.local/share/applications/

The launcher needs an Action line where the quicklist names are defined , for each of the names you need a [Desktop Action name] block which contains Name and Exec lines. Its documented in your link.

You can only go one level deep as far as i'm aware and i've not managed to add anything but launchers to the quicklist.

This has the benefit of ensuring that the menus are available after your program exits and on reboot.

Heres an example that lists various hosts as submenu items from the gnome-terminal icon.

[Desktop Entry]
Name=Terminal
Comment=Use the command line
Keywords=shell;prompt;command;commandline;
TryExec=gnome-terminal
Exec=gnome-terminal
Icon=utilities-terminal
Type=Application
X-GNOME-DocPath=gnome-terminal/index.html
X-GNOME-Bugzilla-Version=3.16.2
Categories=GNOME;GTK;System;TerminalEmulator;
StartupNotify=true
X-GNOME-SingleWindow=false
OnlyShowIn=GNOME;Unity;
Actions=New;host1;host2
X-Ubuntu-Gettext-Domain=gnome-terminal

[Desktop Action New]
Name=New Terminal
Exec=gnome-terminal
OnlyShowIn=Unity

[Desktop Action host1]
Name=SSH to HOST1
Exec=gnome-terminal -e 'ssh host1' -t 'SSH to host1'
OnlyShowIn=Unity

[Desktop Action host2]
Name=SSH to HOST2
Exec=gnome-terminal -e 'ssh host2' -t 'SSH to host2'
OnlyShowIn=Unity