KDE menus (under the hood). Methods to fix if it breaks. Some of this likely pertains to XFCE as well

A lot of poking around and experimentation has brought me to at least a partial understanding of how the dom0 menus function.

I use KDE but I suspect a lot of what I have to say also applies to the default XFCE menu as well.

When a VM (call it my-vm for purposes of this example) is created qvm-appmenus --init and --create is run on it. What gets created as a result of this is:

In $HOME/.local/share/applications, a separate file for each item that that qube has decided should be in the menu (via qvm-features menu-items). This is a desktop file suitable for use on dom0 and this ultimately will be what establishes nodes in the menu.

But also:
in $HOME/.config/menus/applications-merged a single file is created for that vm, named user-qubes-vm-directory-my-vm.menu. If you open that up, it’s a list of all of the files in $HOME/.local/share/applications that have to do with that qube.

When you edit your KDE menu to re-organize the listings for qubes, it’s basically reorganizing references to this latter file, in this case representing the my-vm node in the KDE menu (wherever it might be based on how you organized it). The organization is described in $HOME/.config/menus/applications-kmenuedit.menu…though as time goes on this file collects a lot of cruft, for reasons I’ll get into shortly.

If for some reason you suspect these files are corrupted (as will happen if you do a reset in the KDE menu editor), you can regenerate them with qvm-appmenus --force --update my-vm. (Apparently --force --create is insufficient for this.)

That just leaves one thing and that’s the qvm-appmenus --delete command (which is run when you delete the vm). This will of course wipe out the files in $HOME/.local/share/applications that pertain to the qube named in the command, because those commands no longer exist. What it does not do (and IMHO should) is delete the one fine in $HOME/.config/menus/applications-merged subdirectory that pertains to the VM that got removed.

As a result the next time you open the applications editor in KDE to edit the applications, you will see a “ghost” folder in the menu tree, for the removed VM. The menu itself is smart enough to realize there’s nothing inside this folder and won’t display it, but meanwhile you have this “ghost” folder cluttering up your KDE menu edit application. (And if you delete it, it becomes a branch marked “deleted” in the config file that gets written by this app; part of the cruft I mentioned earlier.) This would be unnecessary if only qvm-appmenus --remove would remove the file for the qube in applications-merged.

I hope this was helpful to someone (though I suspect it’s a bit too disorganized to really be of use).

1 Like

I use the xfce menu and when deleting a VM from QubesManager I have found that the vm.menu file never seems to get deleted, which leaves an entry in the menu that can not be moved or deleted using any menu editing tool that I have found. I simply wrote a script that clears these out periodically in order to deal with this issue as the problem is only seen when editing with a non-Qubes menu editor.

I have also found that these tools seem to have a issue when moving an entry up or down in the list too quickly. If you click to move something up or down before the previous operation has completed you will wind up with a broken Qubes menu because of two different dispatched threads both trying to rewrite the same files. This operation should have been mutexed to prevent this, but it’s not a Qubes problem, so I have not said anything here. I’ll just say be careful how fast to move things around the menus. Broken menus are a pain if you don’t have a terminal in dom0 open.

I’ve not seen the issue you mention with trying to move things up or down too quickly–that’s probably xfce specific. But I can agree it would be infuriating to have to deal with (and you’d wonder why the heck no one in xfce-land ever raised that issue!).

I ultimately ended up writing a 700 or so line bash file (though that can be reduced by 120 lines by removing debug) that loops over all qubes, puts them in arrays corresponding to the different submenus I want to put them in…then writes out a menu file with the qubes arranged how I like them. The only thing it doesn’t do is sort qubes within a submenu the way I want them (which is not alphabetical order).

That’s an awful lot of trouble but I got sick and tired of having to rebuild my menus by hand when they would finally just get too corrupted or complicated to work properly.

OK, I’ve learned a few more things.

Consider a template VM. If you do a qvm-features on it (qvm-features some-template-vm) you will see (amongst a lot of other things) two things, menu-items and default-menu-items. Menu-items is a list of all of the desktop files for things that will show up in the dom0 menu associated with that template. (dom0 will also add, automatically, a link to Settings for that VM.) In my case for my bare-minimal sys-base template upon which all of my other minimal templates are built, it contains “debian-xterm.desktop qubes-start.desktop” That, plus the qube settings, is what shows up in the KDE menu for that qube (and probably for xfce too).

[NOTE: to set these to a list of items, you need to surround the entire list with double quotes, and do not use commas. For example:

qvm-features deb12m-sys-base menu-items "debian-xterm.desktop qubes-start.desktop"

To clear the list use

qvm-features deb12m-sys-base menu-items ""

And another note. If you have no idea what the desktop file is named for some application you want to put in one of these lists, go to Settings->Applications, put the application in the right hand window, Apply or OK, then run qvm-features on the qube; you should be able to figure out which item in the menu-items list is the desktop file name you want.]

But what is default-menu-items for? I’ve wondered this for a long time and finally realized the answer. If you create an AppVM based on this template, the AppVM’s menu-items gets set to whatever is in the template’s default-menu-items. So, let’s say you have a minimal template on which you’ve installed firefox. You probably don’t want firefox to show up in the menu for the template but you almost certainly will want to see firefox in the AppVM’s menu. So this is perfect: set menu-items for the template to be the sort of stripped-down list I have, then set default-menu-items for the template, to be a longer list, including, of course, firefox. All you have to do is create an AppVM based on the template, and it’s menu is already set up properly! (Note: If the template has a blank default-menu-items but has something in menu-items, then the AppVM will get menu-items copied directly from the template.) default-menu-items in the appvm is unset.

However, that’s only for an AppVM that isn’t a disposable template. If it IS a disposable template, it gets complicated.

There are two different ways to do a disposable template, and they’re not really mutually exclusive. One is the case where you are going to create a named disposable (on most installations sys-firewall is an example of a named disposable) from the disposable template. (I’m going to start abbreviating that “dvmt” for “disposable virtual machine template” just to save my fingers and your eyes from constant repetition.) The other is where you plan to “fire up” the dvmt in such a way that it creates un named disposables on the fly, e.g., disp1234, disp7734, etc. (And you can use the same dvmt in both ways; create a bunch a named disposables and be ready to spawn a disp1234 from it as well.

In both of these cases, you’re using the dvmt to create a different virtual machine; there’s also the possibility of running the template itself exactly as if it were just a plain old AppVM. (This is probably not something you will want to do often, except perhaps to change a configuration so that it will show up in all disp1234s you spawn in the future.)

These will look different in the KDE menu.

  • A regular APPVM will be labeld “Qube: my-regular-appvm” and the icon (if visible) will be a single big cube

  • A dvmt shown as itself…in other words, you’d run the dvm template itself, will be listed as “Template (disp): my-dvmt” and have a double cube icon, but this time it’s the lower right cube that looks solid.

  • A named disposable will be labeled “Qube: my-named-disposable” but the icon will be the double qube with the upper left solid and the lower right a ghost image.

  • A dvmt that you would click on to fire up a disp1234 disposable will be labeled “disposable: my-dvmt” and will have a double qube icon, again with the upper left cube looking solid. Note that the name shown in the menu is the same as it is for the menu item where you run the template itself.

  • And finally (for completeness) an actual template vm shows as “Template: my-template” and has the double cube icon, with the lower right qube looking solid. The difference is this one doesn’t say “Template (disp)”

{More coming soon…]

OK so dvmts is where it gets messy. I’m going to show the steps I have found I have to go through, manually (command line), which tells me that the gui utilities probably do the same things behind the scenes.

Like a regular AppVM, you create it from a template, like this (command line in dom0).

qvm-create --label blue --template my-template my-dvmt

But right now in spite of the name, it’s just a regular AppVM. It shows up in the menu as “Qube: my-dvmt” with the single cube icon.

(Checking with qvm-features my-dvmt one can verify that menu-items is set to the template’s default-menu-items and the new qube’s default-menu-items isn’t listed at all.)

Make it a disposable template:

qvm-prefs my-dvmt template_for_dispvms true

Note that this, by itself, does not change the way the qube appears in the menu. There’s more to be done.

You need to set my-dvmt’s default-menu-items to whatever is in menu-items. And set menu-items to blank. If on the command line a foolproof way to do that is echo the menu-items into the command to set default-menu-items

qvm-features my-dvmt default-menu-items "`qvm-features my-dvmt menu-items`"
qvm-features my-dvmt menu-items ""

And then (not sooner) you need to set appmenus-dispvm to either 0 or 1.

What does appmenus-dispvm do? It governs whether the template shows up in the menu as disposable: my-dvmt. In other words whether it shows up as a launcher for unnamed disposables (disp1234s). If set to 1, it shows up, if set to 0, it won’t. Of course right now it’s not showing up, and we want it to stay that way, but we need to explicitly set it to zero at this time.

qvm-features my-dvmt appmenus-dispvm 0

or

qvm-features my-dvmt appmenus-dispvm 1

(If you’re using a salt formula, you can do all of these at the same time (default-menu-items, menu-items and appmenus-dispvm), just don’t do appmenus-dispvm in a separate state before you adjust the menu!)

If you wait for a bit, suddenly my-dvmt shows up as “Template (disp): my-dvmt” in the menu, which is the way to run the template itself. However, the menu has nothing in it since menu-items is blank. Also, if we have appmenus-dispvm set to 1 (we want the disposable disp1234 launcher), it’s still not there.

So we have to patch it.

First, set the menu back the way it was:

qvm-features my-dvmt menu-items "`qvm-features my-dvmt default-menu-items`"
qvm-features my-dvmt default-menu-items ""

(If you plan to create named dvms, set default-menu-items to whatever you want to have in the named dvm’s menu…usually, you just leave it alone in this case, rather than setting it to “”)

Now you can call qvm-sync-appmenus (you will have to start the qube first).

qvm-start my-dvmt
qvm-sync-appmenus my-dvmt
qvm-shutdown my-dvmt

Now, the menus for “Template (disp): my-dvmt” are correct AND if appmenus-dispvm was set to 1, you see “Disposable: my-dvmt” with correct menus. (Settings doesn’t appear, and neither does start qube. This makes sense because this qube doesn’t exist (nothing to set) until it launches, and it launches to run a specific app and then shuts down when that app is closed; there’s no way to just start it because then it’s not running anything so (at best) it would simply shut down again.)

This is a very convoluted process and I apologize for that…if you can find a shorter sequence that sets the menu up right, let me know. I’ve tried leaving various steps out only to find out it won’t quite work in some way or another.

Compared to this creating a named DVM is simple:

qvm-create --label blue --class DispVM --template my-dvmt my-named-dvm

At this point all menus should work. There are two caveats, however:

  1. If you created your template (at the very beginning) by cloning another template, BEWARE. There’s a bug being worked, basically when you clone a template the new template’s menu-items become what the source template’s default-menu-items was. This would be good behavior creating an appvm, but it’s bad behavior cloning templates. Check to ensure this did not happen with qvm-features new-template; if it did, then fix it before proceeding.

  2. If anything you installed in the template was done simply by copying files, rather than dnf install or apt install, you need to run this in the template immediately afterwards:
    /usr/lib/qubes/qubes-trigger-sync-appmenus.sh
    which forces dom0 to recognize your scripts or hand copied executables as if they had been “professionally” installed via a package.