After quite a lot of positive feedback from my last post I’ll write some more about custom plugins. Next up is returning custom applications into the installed list. The use case here is a proprietary software distribution method that installs custom files into your home directory, but you can use your imagination for how this could be useful.
The example here is all hardcoded, and a true plugin would have to derive the details about the GsApp, for example reading in an XML file or YAML config file somewhere. So, code:
#include <gnome-software.h> void gs_plugin_initialize (GsPlugin *plugin) { gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_BEFORE, "icons"); } gboolean gs_plugin_add_installed (GsPlugin *plugin, GsAppList *list, GCancellable *cancellable, GError **error) { g_autofree gchar *fn = NULL; g_autoptr(GsApp) app = NULL; g_autoptr(AsIcon) icon = NULL; /* check if the app exists */ fn = g_build_filename (g_get_home_dir (), "chiron", NULL); if (!g_file_test (fn, G_FILE_TEST_EXISTS)) return TRUE; /* the trigger exists, so create a fake app */ app = gs_app_new ("example:chiron.desktop"); gs_app_set_management_plugin (app, "example"); gs_app_set_kind (app, AS_APP_KIND_DESKTOP); gs_app_set_state (app, AS_APP_STATE_INSTALLED); gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "Chiron"); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "A teaching application"); gs_app_set_description (app, GS_APP_QUALITY_NORMAL, "Chiron is the name of an application.\n\n" "It can be used to demo some of our features"); /* these are all optional */ gs_app_set_version (app, "1.2.3"); gs_app_set_size_installed (app, 2 * 1024 * 1024); gs_app_set_size_download (app, 3 * 1024 * 1024); gs_app_set_origin_ui (app, "The example plugin"); gs_app_add_category (app, "Game"); gs_app_add_category (app, "ActionGame"); gs_app_add_kudo (app, GS_APP_KUDO_INSTALLS_USER_DOCS); gs_app_set_license (app, GS_APP_QUALITY_NORMAL, "GPL-2.0+ and LGPL-2.1+"); /* create a stock icon (loaded by the 'icons' plugin) */ icon = as_icon_new (); as_icon_set_kind (icon, AS_ICON_KIND_STOCK); as_icon_set_name (icon, "input-gaming"); gs_app_set_icon (app, icon); /* return new app */ gs_app_list_add (list, app); return TRUE; }
This shows a lot of the plugin architecture in action. Some notable points:
- The application ID (
example:chiron.desktop
) has a prefix ofexample
which means we can co-exist with any package or flatpak version of the Chiron application, not setting the prefix would make the UI confused if more than onechiron.desktop
got added. - Setting the management plugin means we can check for this string when working out if we can handle the install or remove action.
- Most applications want a kind of
AS_APP_KIND_DESKTOP
to be visible as an application. - The origin is where the application originated from — usually this will be something like Fedora Updates.
- The
GS_APP_KUDO_INSTALLS_USER_DOCS
means we get the blue “Documentation” award in the details page; there are many kudos to award to deserving apps. - Setting the license means we don’t get the non-free warning — removing the 3rd party warning can be done using
AS_APP_QUIRK_PROVENANCE
- The
icons
plugin will take the stock icon and convert it to a pixbuf of the correct size.
To show this fake application just compile and install the plugin, touch ~/chiron
and then restart gnome-software.
By filling in the optional details (which can also be filled in using gs_plugin_refine_app()
(to be covered in a future blog post) you can also make the details page a much more exciting place. Adding a set of screenshots is left as an exercise to the reader.
For anyone interested, I’m also slowly writing up these blog posts into proper docbook and uploading them with the gtk-doc files here. I think this documentation would have been really useful for the Endless and Ubuntu people a few weeks ago, so if anyone sees any typos or missing details please let me know.
const gchar **
gs_plugin_order_before (GsPlugin *plugin)
{
static const gchar *deps[] = { “icons”, NULL };
return deps;
}
Is that really the return type you want? The characters
are constant, but the pointers to them are not.
Suggestion: const gchar * const*
Hey, good catch! I started to migrate the code to “const gchar * const*” and then figured, “what if the plugin wants to change the list at startup” — and apart from leaking memory there was no good fix. I’ll think more about this over the weekend.
The type of deps can stay unchanged even if you change
the function return type.
I think I’ve fixed this in a much nicer way: it’s tons simpler now: https://git.gnome.org/browse/gnome-software/commit/?id=7ac55cfb3993f146a2a2078535a8512f405d163b