The sound of one head banging...

Linux is wonderful. Honest. Really, it is. Most of it works most of the time, which is pretty good. And it doesn't get any cheaper than free.

But.... a few things are HEAD BANGINGLY BAD !!!

At the focal point of this Linux rant is the freedesktop menu system.

Freedesktop is a set of standards, which aims to define the relationship between applications and the desktop environments of Unix-like operating systems. In other words, it's an attempt to ensure that applications can be integrated into a desktop environment in a standard way, so that applications need to know as little as possible about the desktop, and can be portable across environments. It's been around in some form ( very largely the same form ) for 20 years now.

It sounds fantastic ! What could be worse than a heterogeneous set of desktop environments where apps had to be installed or configured differently for every one ?

Well it's true, that would be a Bad Thing.

However, the freedesktop menu and category system sucks. It harks back to an age where Unix user environments were controlled by sysadmins, and is not a good fit for the more usual Linux desktop environment of today, which is more often a sudo - enabled single user with the capability to install applications locally at will. Indeed, this user is frequently the only person who installs applications other than the distro itself.

There is still a need for a standard to allow applications to integrate with different desktops, but in fact the category/menu part of freedesktop is not essential for this - these are simply a 'presentation layer' design choice that freedesktop imposes on the user ( and indeed, on the desktop implementation ).

The way in which it uses categories to provide some initial default context for an application is mildly useful, but having two orthogonal classification systems ( categories and menus ), together with a multiple categories per application, is a PITA that gives rise to confusion and complication far more often than it is useful.

Some distro's have completely changed the app launching model away from the use of a menu system, but many still rely on this technique.

Existing tools for managing desktop menus are not focused on end user use cases, but on exposing the underlying freedesktop data architecture. This makes them hard to understand and use, because the freedesktop architecture is complicated, largely irrelevant to the user, and makes many assumptions. It's hard for the user to structure their app launching environment in a way that suits them.

Some use cases

Therefore as an Xubuntu user using xfce I've begun to contemplate designing my own application access tool, because MenuLibre has made me yell at my screen and bang my head once too often.

One way to start developing something is to consider 'use cases'. These are just statements, made using varying degrees of formality, which capture 'atomic' things that a user may wish to do with a system, from the user's perspective. The latter part is critical - developers are often terribly bad at creating use cases, because they are automatically building a design in their heads, and this conditions the use cases they see, and the expression of those use cases. However, for personal projects like this it's really Hobson's Choice.

So here are some things I want to do.

U1. Synchronise with the system.

When I trigger this behaviour via the GUI, I want the application to show me applications which have been removed and applications which have been added since the last synchronisation, but no automatic menu updates should occur.

U2. Optionally, synchronise with the system automatically.

If I set an appropriate option, then on opening the application I want the application to automatically remove from any menu any application which is no longer present, and to display all applications which have been added since the last synchronisation but not put them in menus.

U3. Add an app manually.

Via a suitable GUI interface, I want to add an application to a menu in a manner that allows it to be launched from that menu. This interface should not depend on the existence of a desktop file.

U4. Create a new top level menu.

Via a suitable GUI interface, I want to be able to create a top level menu ( located immediately beneath the root of the menu system ), which will initially be empty.

U5. Create a new sub menu.

Via a suitable GUI interface, I want to be able to create a sub menu, located in a non-top-level menu, which will initially be empty.

U6. Associate an Icon with a menu.

Via a suitable GUI interface, I want to be able to associate an icon with a menu.

U7. Move a menu to another Menu.

Using a drag and drop technique, I want to be able to move one menu to another menu.

U8. Delete menus and their contents.

Via a suitable GUI interface, I want to be able to select a menu and delete it together with it's contents.

U9. Move an app from one menu to another.

Using a drag and drop technique, I want to be able to move an app from one menu to another menu.

U10. Have an app in more than one menu ( rare ).

I want to be able to duplicate an app in another menu via copy and paste.

U11. Delete an app from a menu.

Via a suitable GUI interface, I want to be able to select an app and delete it from that menu.

U12. Delete an app from the menu system entirely.

Via a suitable GUI interface, I want to be able to select an app and delete it from all menus.

U13. Associate an icon with an app.

Via a suitable GUI interface, I want to be able to associate an icon with an app.

U14. Launch an app.

Via a suitable GUI interface, I want to be able to click on an app and cause it to execute whilst leaving the menu displayed.

U15. Launch an app as sudo.

Via a suitable GUI interface, I want to be able to click on an app and cause it to execute with sudo privilege whilst leaving the menu displayed.

U16. View the location of an app.

I want to be able to view the location in the filesystem of the executable that is used when an app is launched.

U17. View/edit the invocation of an app.

I want to be able to define the command line that is used to launch an app.

U18. View only icons, or icons and Names.

In the GUI, I want to be able to choose whether I see only the icons that represent menus and apps, or a combination of icons and textual names.

U19. Be informed about missing executables

I want the GUI to provide an indication if the executable associated with an app is missing ( i.e. the app has been moved or removed by some means external to this program ).

U20. Skin the interface ( maybe )

I want to be able to choose between alternative visual appearances for this program.

U21. Export the menu structure

I want to be able to export the menu structure in the form of freedesktop XML.

U22. Notes per app

I want to be able to attach textual notes to a menu item that are visible ( and editable ) on request.

U23. Synchronisation triggered by addition/removal of an application

I want to be able to be able to detect the addition and deletion of applications from the system, and make appropriate changes to the database/menus.

U24. Dbus interface

I want to be able to obtain information from the SQLite database via a dbus interface. Since I'm going to the trouble of maintaining this resource, it seems reasonable to share it with others.

Additional requirements

I have some requirements for the solution that are not obvious from the use cases.

R1. Minimal dependency on freedesktop

Clearly, since I'm attempting to get away from the concepts of menu and category as laid down by freedesktop, I should be trying to avoid assumptions based on freedesktop. But the key here is 'minimal', not 'zero'. I want my app to exist in environments where freedesktop is assumed, so I must deal with the fact that information about apps will be present in places and forms mandated by freedesktop. In a way, my app is simply a different way of interpreting information supplied in freedesktop's 'desktop' files.

R2. Sane defaults

Picking defaults is one of the banes of a developer's life, but sane defaults are essential for usability. 'Sane' means that they are values which the user could reasonably have chosen by themselves. In particular, when the application is first started, it should not require the user to create an entire application menu system from scratch. Therefore initially the application shall derive a set of menus using categories supplied in desktop files. This initial start is the only point in time where freedesktop categories are referenced directly for structuring the UI.

R3. Persistence

The application does not depend on parsing the entire collection of desktop files every time it starts ( this is optional, see U2 ). Therefore it must have a persistent store of it's own for this information.

Design

I'm going to refer to 'design' here, rather than 'architecture', because I want to dodge the question 'what is architecture ?' 🙂. On the one hand, an architecture can be used as a convenient way to draw lines around chunks of the design task. And I hold it to be self evident that everything 'has architecture', even if it is trivial. But in the case of a single small application like this, there's little point devoting significant effort to the creation of powerful abstractions. However, I will be attempting to capture the design in UML ( despite the fact that there are no good free UML tools for Linux :( )).

At this point, before I start any refinement, the design essentially looks like this :

Initialisation

Trawl the filesystem for desktop files, using the standard freedesktop paths. Filter out any desktop files that do not represent apps. Build an SQLite database of the contents of those files. Filter out any duplicates. Pick one category to associate with the app. Record this category name as the menu name containing the app. Pick a random icon to associate with the menu.

There is a design choice here. I've chosen to use an SQLite database for this information. Freedesktop in fact maintains a similar aggregation of information in XML form. I could also store this information in a flat XML file a la freedesktop. This might be said to make it more accessible, and there is no shortage of tools for processing XML.

But my judgement here is that this is a database, not a document. By treating it as such, I get all the database processing tools associated with SQL, or at least with SQLite. For viewing purposes, there are numerous free tools that will happily inspect an SQLite database if necessary.

Another design choice is whether this application is actually client-server. It may be that the thing that maintains the SQLite database should act as a server, getting started before the desktop starts, and hence being available immediately after the user logs in. The GUI is then a client, which may be launched automatically by the desktop.

Creating a client server solution has more complications to it than a simple application, and I'm not sure that there is really a significant performance consideration given the speeds of typical systems. Also, the database is user-specific, and the server design would need to deal with the multi-user scenario. On the whole, client server seems more complicated than it is likely to be worth. But maintaining a clear separation of GUI and business logic will leave that option open if it should turn out to be useful.

And finally, there's a choice about whether the database should reside, in normal use, on disk or in memory. It's going to be a small database, so arguably speed is not so important. And it has to be persisted, so there has to be a disk version of it. But because it's small, that also means it should be no problem to hold the information it contains in memory. If I hold it in memory, either I use SQLite's built in ability to hold a database in memory, or I use the disk database to initialise a vector containing my own objects. The route out of this puzzle is via laziness 🙂. If I pull the database into memory using SQLite, and try to avoid converting between database records and objects, I'll have a quick solution and probably be able to avoid some work.

GUI

The GUI is a QML defined UI. The main task of this UI is to display a menu structure based on the content of the SQLite database, and to provide dialogs in support of the business logic.

The design issue here is that although QML is a perfectly fine GUI specification/design tool, it means that I have a significant dependency on Qt. Qt is a big, heavyweight thing. If I were just intending that my app worked for my desktop ( xfce ), then I might be able to make a much lighter tool. But I'm not 🙂. I would like this app to work for most desktops that depend on freedesktop. I think QML/Qt is one way of addressing that problem.

Business logic

There isn't much. The majority of use cases are concerned with viewing and manipulating the SQLite database content, and these must have associated logic.

One of the more involved pieces of logic will be exporting my SQLite table(s) in the form of freedesktop menu XML. The intention here is to permit the application to be treated as a 'sort of' freedesktop menu editor - a user can, if they so wish, create a menu structure in my application and then transfer that structure to an application that assumes freedesktop use ( like many of the application launchers built in to existing desktops ). However, this is a 'would be nice' feature, and I shan't sweat about it - if it can be done easily, great, otherwise it's no big deal to drop it.

Another potentially complex thing comes from U23. The basic idea behind U23 is to avoid the need for users to trigger a synchronisation explicitly whenever they add or remove applications ( i.e. add or remove applications from the system, as opposed to from my application menus ). There are lots of ways this might be done.

But what's it called ?

🙂 It needs a name. I shall call it 'memenu', because I don't want it to be confused with an Italian fast food delivery system, and because of the ( weak ) play on words ( meme - new ).

© Mark de Roussier 2021, all rights reserved.