How to patch the Workrave GNOME extension to work on NixOS without using global environment variables?

I’ve been trying to patch up the Workrave GNOME extension so that it works under NixOS, so that I can provide a solution to my own bug report for the Nix Workrave package. Here’s what I’ve managed so far.

Currently, my Workrave package is compiled with the following overlay:

nixpkgs.overlays = [
    (final: prev: {
      workrave = prev.workrave.overrideAttrs (
        finalAttrs: prevAttrs: {
          configureFlags = # prevAttrs.configureFlags ++
            [ "--enable-gnome45" ];
          buildInputs = prevAttrs.buildInputs ++ [ pkgs.gtk4 ];
        }
      );
    })
  ];

This much is needed in order to get an extension installed that can work on GNOME 45 and later.

I then started working on my own version of the extension in ~/.local/share/gnome-shell/extensions that’s a copy of the original Workrave one, but renamed. The extension directory is renamed workrave2-hack@workrave.org, and in metadata.json, the values of the keys "extension-id", "uuid", and "name" are "workrave2-hack", "workrave2-hack@workrave.org", and "Workrave2-hack", respectively.

Following examples from the Nixpkgs manual, in extension.js, I replaced the line

import Workrave from "gi://Workrave?version=2.0";

with

import GIRepository from 'gi://GIRepository';
GIRepository.Repository.prepend_search_path('/nix/store/j4aw5jqby0vwyinjayjidxldlqs0v7q9-workrave-1.10.53/lib/girepository-1.0');
const Workrave = (await import("gi://Workrave?version=2.0")).default;

Yes, for now, the argument of prepend_search_path is a hardcoded path to a /nix/store location, but I figured that once I got the basics working, I could set up a patch with replaceVars, etc., to do things properly.

However, this was not enough. When I debugged the extension by running a nested GNOME Wayland session, it crashed once this hacked extension was activated, leaving behind the following errors:

(gnome-shell:8097): GLib-GIO-ERROR **: 17:19:18.767: Settings schema 'org.workrave.gui' is not installed
== Stack trace for context 0x3cb11010 ==
#0       3cc09ab0 i   file:///home/jjramsey/.local/share/gnome-shell/extensions/workrave2-hack@workrave.org/extension.js:175 (22f25dcc0380 @ 50)
#1       3cc09a10 i   resource:///org/gnome/shell/ui/panelMenu.js:10 (22f25dc3d290 @ 27)
#2       3cc09950 i   resource:///org/gnome/shell/ui/panelMenu.js:95 (22f25dc3d5b0 @ 27)
#3       3cc09890 i   file:///home/jjramsey/.local/share/gnome-shell/extensions/workrave2-hack@workrave.org/extension.js:171 (3683a98996f0 @ 27)
#4       3cc097e0 i   file:///home/jjramsey/.local/share/gnome-shell/extensions/workrave2-hack@workrave.org/extension.js:534 (3683a986db00 @ 36)
#5       3cc09738 i   resource:///org/gnome/shell/ui/extensionSystem.js:266 (22f25dc22a60 @ 423)
#6       3cc09698 i   self-hosted:1423 (22f25dcf4ce0 @ 30)
#7   7fff12558d20 b   self-hosted:804 (22f25dcf4d80 @ 15)
#8       3cc09608 i   resource:///org/gnome/shell/ui/init.js:21 (3683a987ea60 @ 48)

What did help was including /nix/store/j4aw5jqby0vwyinjayjidxldlqs0v7q9-workrave-1.10.53/share/gsettings-schemas/workrave-1.10.53 in the XDG_DATA_DIRS path, but this still left the extension relying on some outside global state, which is not the NixOS way.

I then thought I could get rid of this dependence on XDG_DATA_DIRS after reading Gnome extention Hanabi on nixos - #12 by jtojnar, which said,

I then used GNOME JavaScript docs as guide to putting the schemas in the extension directory and setting metadata.json accordingly. First, I created a symbolic link schemas in that directory, which pointed to the /nix/store/j4aw5jqby0vwyinjayjidxldlqs0v7q9-workrave-1.10.53/share/gsettings-schemas/workrave-1.10.53/glib-2.0/schemas directory. Next, I saw that in the example from the GNOME docs that the example schema,

<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
  <schema id="org.gnome.shell.extensions.example" path="/org/gnome/shell/extensions/example/">
    <key name="show-indicator" type="b">
      <default>true</default>
    </key>
  </schema>
</schemalist>

had "org.gnome.shell.extensions.example" as the schema id, and in the example metadata:

{
    "uuid": "example@gjs.guide",
    "name": "Example Extension",
    "description": "An example extension with preferences",
    "shell-version": [ "45" ],
    "url": "https://gjs.guide/extensions",
    "gettext-domain": "example@gjs.guide",
    "settings-schema": "org.gnome.shell.extensions.example"
}

the value for the key "settings-schema" was set to that schema id.

Since the error message from GLib said, “Settings schema ‘org.workrave.gui’ is not installed”, and one of the XML files in /nix/store/j4aw5jqby0vwyinjayjidxldlqs0v7q9-workrave-1.10.53/share/gsettings-schemas/workrave-1.10.53/glib-2.0/schemas, org.workrave.gui.gschema.xml had the schema id "org.workrave.gui", I set the “settings-schema” value in my metadata.json file to "org.workrave.gui".

Unfortunately, this did not help. My hacked extension still doesn’t work without modifying XDG_DATA_DIRS.

What am I missing here? How do I get GNOME shell to find the schemas properly?

ETA: Well, I’ve found an answer that at least works on the local level, thanks to these links:

While having the schemas directory under the extensions directory doesn’t work, putting links to the schemas (both compiled and not) under ~/.local/share/glib-2.0 does. Unfortunately, that also means that if any other files are added to that directory, glib-compile-schemas needs to be re-run.

And of course, that won’t work for system-wide extensions. :expressionless:

Not sure why the GNOME Shell docs don’t agree with the actual shell implementation. :man_shrugging:

ETA again: Judging from my inspections of the Dash-to-Dock and Dash-to-Panel, it looks like schemas with IDs that begin with “org.gnome.shell.extensions” do get read from the extension directories. I guess it’s just the schemas that pertain to external apps that don’t? :confused:

1 Like

Well, I figured out how to patch Workrave, both the JavaScript extension and the C and C++ source, and an overlay implementing it is in a comment to the issue I started.