--- /dev/null
+from gi.repository import Gtk
+import os
+import subprocess
+
+import gi
+gi.require_version("Gtk", "4.0")
+
+
+def on_edit(_):
+ config_dir = os.path.join(
+ os.environ.get('XDG_CONFIG_HOME', os.path.expanduser('~/.config')),
+ 'nixpkgs',
+ 'overlays')
+ os.makedirs(config_dir, exist_ok=True)
+ config_file = os.path.join(config_dir, 'userPackages.nix')
+ try:
+ with open(config_file, mode="x") as f:
+ f.write('''final: prev: {
+ userPackages = final.buildEnv {
+ name = "userPackages";
+ paths = (with final; [
+
+
+
+ ];
+ };
+}
+''')
+ except FileExistsError:
+ pass
+ subprocess.run(['xdg-open', config_file], check=True)
+
+
+def try_exec_terminal(terminal, args):
+ try:
+ os.execvp(terminal, [terminal] + args)
+ except FileNotFoundError:
+ pass
+
+
+def on_apply(_):
+ command = ['nix-env', '-riA', 'nixos.userPackages']
+ command_string = ' '.join(command)
+ close_string = ''' && read -p "SUCCESS: Press ENTER to close this window" || read -p "FAILURE: Press ENTER to close this window"'''
+ # This should be a simple `xdg-terminal` invocation, but as of 2025,
+ # xdg-terminal is extremely broken in Gnome:
+ # * It doesn't cause a terminal window to appear
+ # * It doesn't run the given command
+ # * It exits with status 0, so you can't even tell that it failed
+ # * There's no way for the user to configure their preferred terminal?
+ # So we just try launching a whole bunch of terminals until we find one
+ # that works
+ if os.fork() == 0:
+ try_exec_terminal('kitty', ['sh', '-c', command_string + close_string])
+ try_exec_terminal(
+ 'alactritty', [
+ '-e', 'sh', '-c', command_string + close_string])
+ try_exec_terminal('kgx', ['--'] + command)
+ try_exec_terminal(
+ 'konsole', [
+ '-e', 'sh', '-c', command_string + close_string])
+ try_exec_terminal('xfce4-terminal', ['--hold', '-e', command_string])
+ try_exec_terminal('st', ['sh', '-c', command_string + close_string])
+ try_exec_terminal(
+ 'urxvt', [
+ '-e', 'sh', '-c', command_string + close_string])
+ try_exec_terminal(
+ 'xterm', [
+ '-e', 'sh', '-c', command_string + close_string])
+
+ # Don't even try gnome-terminal. Sometimes it will start, but not run the command,
+ # and exit with status 0 so we wouldn't even be able to tell that there was a problem.
+ # try_exec_terminal('gnome-terminal', ['--', 'sh', '-c', command_string + close_string])
+
+ # As a last resort, run the command directly, without a terminal, where
+ # the user probably can't see it. :(
+ os.execvp(command[0], command)
+
+
+def on_activate(app):
+ win = Gtk.ApplicationWindow(application=app)
+ box = Gtk.Box()
+ box.set_orientation(Gtk.Orientation.VERTICAL)
+ edit = Gtk.Button(label="Edit Configuration")
+ apply = Gtk.Button(label="Apply Configuration")
+ edit.connect('clicked', on_edit)
+ apply.connect('clicked', on_apply)
+ box.append(edit)
+ box.append(apply)
+ win.set_child(box)
+ win.present()
+
+
+def main():
+ app = Gtk.Application(application_id='net.chkno.nix-env-apps')
+ app.connect('activate', on_activate)
+ app.run(None)
+
+
+if __name__ == '__main__':
+ main()