Compare commits
	
		
			3 Commits
		
	
	
		
			45bda5b588
			...
			73f5a690bb
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 73f5a690bb | |||
| 54db751e23 | |||
| 85299b65dc | 
@@ -15,10 +15,21 @@ let
 | 
				
			|||||||
    url = "https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad";
 | 
					    url = "https://distro.ibiblio.org/slitaz/sources/packages/d/doom1.wad";
 | 
				
			||||||
    hash = "sha256-HX1DvlAeZ9kn5BXguPPinDvzMHXoWXIYFvZSpSbKx3E=";
 | 
					    hash = "sha256-HX1DvlAeZ9kn5BXguPPinDvzMHXoWXIYFvZSpSbKx3E=";
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  doomNcurses = pkgs.writeShellScript "doom-ncurses" ''
 | 
					  # doomNcurses = pkgs.writeShellScript "doom-ncurses" ''
 | 
				
			||||||
    SDL_AUDIODRIVER=null SDL_VIDEODRIVER=caca CACA_DRIVER=ncurses exec ${pkgs.chocolate-doom2xx}/bin/chocolate-doom -iwad ${doomWad}
 | 
					  #   SDL_AUDIODRIVER=null SDL_VIDEODRIVER=caca CACA_DRIVER=ncurses exec ${pkgs.chocolate-doom2xx}/bin/chocolate-doom -iwad ${doomWad}
 | 
				
			||||||
 | 
					  # '';
 | 
				
			||||||
 | 
					  # lockCmd = "swaylock-plugin --command-each '${pkgs.windowtolayer}/bin/windowtolayer -- alacritty -e ${doomNcurses}'";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  doomsaver = pkgs.runCommand "doomsaver" {
 | 
				
			||||||
 | 
					    inherit (pkgs) windowtolayer;
 | 
				
			||||||
 | 
					    chocoDoom = pkgs.chocolate-doom2xx;
 | 
				
			||||||
 | 
					    python = pkgs.python3.withPackages (ps: [ ps.filelock ]);
 | 
				
			||||||
 | 
					    inherit doomWad;
 | 
				
			||||||
 | 
					  } ''
 | 
				
			||||||
 | 
					    mkdir -p "$out"/bin
 | 
				
			||||||
 | 
					    substituteAll ${./screensaver.py} "$out"/bin/doomsaver
 | 
				
			||||||
 | 
					    chmod +x "$out"/bin/doomsaver
 | 
				
			||||||
  '';
 | 
					  '';
 | 
				
			||||||
  lockCmd = "swaylock-plugin --command-each '${pkgs.windowtolayer}/bin/windowtolayer -- alacritty -e ${doomNcurses}'";
 | 
					 | 
				
			||||||
in
 | 
					in
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  options.my.gui = {
 | 
					  options.my.gui = {
 | 
				
			||||||
@@ -45,7 +56,14 @@ in
 | 
				
			|||||||
            nil # nix language server
 | 
					            nil # nix language server
 | 
				
			||||||
            zls # zig language server
 | 
					            zls # zig language server
 | 
				
			||||||
            rust-analyzer
 | 
					            rust-analyzer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            cowsay
 | 
				
			||||||
 | 
					            fortune
 | 
				
			||||||
 | 
					            terminaltexteffects
 | 
				
			||||||
 | 
					            screenfetch
 | 
				
			||||||
            neofetch
 | 
					            neofetch
 | 
				
			||||||
 | 
					            cmatrix
 | 
				
			||||||
 | 
					            doomsaver
 | 
				
			||||||
          ];
 | 
					          ];
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -198,7 +216,7 @@ in
 | 
				
			|||||||
                  in
 | 
					                  in
 | 
				
			||||||
                  lib.mkOptionDefault {
 | 
					                  lib.mkOptionDefault {
 | 
				
			||||||
                    "${mod}+d" = null;
 | 
					                    "${mod}+d" = null;
 | 
				
			||||||
                    "${mod}+l" = "exec ${lockCmd}";
 | 
					                    "${mod}+l" = "exec ${doomsaver}/bin/doomsaver";
 | 
				
			||||||
                    "${mod}+x" = "exec ${cfg.menu}";
 | 
					                    "${mod}+x" = "exec ${cfg.menu}";
 | 
				
			||||||
                    "${mod}+Shift+x" = "exec rofi -show drun";
 | 
					                    "${mod}+Shift+x" = "exec rofi -show drun";
 | 
				
			||||||
                    "${mod}+q" = "kill";
 | 
					                    "${mod}+q" = "kill";
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										199
									
								
								home-manager/modules/gui/screensaver.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										199
									
								
								home-manager/modules/gui/screensaver.py
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,199 @@
 | 
				
			|||||||
 | 
					#!@python@/bin/python
 | 
				
			||||||
 | 
					import argparse
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					import signal
 | 
				
			||||||
 | 
					import subprocess
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import filelock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Screensaver:
 | 
				
			||||||
 | 
					    def __init__(self, cmd, env=None, weight=1):
 | 
				
			||||||
 | 
					        self.cmd = cmd
 | 
				
			||||||
 | 
					        self.weight = weight
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if env is not None:
 | 
				
			||||||
 | 
					            self.env = os.environ.copy()
 | 
				
			||||||
 | 
					            for k, v in env.items():
 | 
				
			||||||
 | 
					                self.env[k] = v
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.env = None
 | 
				
			||||||
 | 
					        self.proc = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start(self):
 | 
				
			||||||
 | 
					        assert self.proc is None
 | 
				
			||||||
 | 
					        self.proc = subprocess.Popen(self.cmd, env=self.env)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wait(self):
 | 
				
			||||||
 | 
					        assert self.proc is not None
 | 
				
			||||||
 | 
					        self.proc.wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self, kill=False):
 | 
				
			||||||
 | 
					        assert self.proc is not None
 | 
				
			||||||
 | 
					        if kill:
 | 
				
			||||||
 | 
					            self.proc.kill()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.proc.terminate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DoomSaver(Screensaver):
 | 
				
			||||||
 | 
					    wad = '@doomWad@'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, demo_index, weight=1.5):
 | 
				
			||||||
 | 
					        super().__init__(
 | 
				
			||||||
 | 
					            ['@chocoDoom@/bin/chocolate-doom',
 | 
				
			||||||
 | 
					             '-iwad', self.wad,
 | 
				
			||||||
 | 
					             '-demoloopi', str(demo_index)],
 | 
				
			||||||
 | 
					            env={
 | 
				
			||||||
 | 
					                'SDL_AUDIODRIVER': 'null',
 | 
				
			||||||
 | 
					                'SDL_VIDEODRIVER': 'caca',
 | 
				
			||||||
 | 
					                'CACA_DRIVER': 'ncurses',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            weight=weight,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self):
 | 
				
			||||||
 | 
					        super().stop(kill=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TTESaver(Screensaver):
 | 
				
			||||||
 | 
					    effects = (
 | 
				
			||||||
 | 
					        'beams,binarypath,blackhole,bouncyballs,bubbles,burn,colorshift,crumble,'
 | 
				
			||||||
 | 
					        'decrypt,errorcorrect,expand,fireworks,middleout,orbittingvolley,overflow,'
 | 
				
			||||||
 | 
					        'pour,print,rain,randomsequence,rings,scattered,slice,slide,spotlights,'
 | 
				
			||||||
 | 
					        'spray,swarm,synthgrid,unstable,vhstape,waves,wipe'
 | 
				
			||||||
 | 
					    ).split(',')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, cmd, env=None, weight=1):
 | 
				
			||||||
 | 
					        super().__init__(cmd, env=env, weight=weight)
 | 
				
			||||||
 | 
					        self.running = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start(self):
 | 
				
			||||||
 | 
					        self.running = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wait(self):
 | 
				
			||||||
 | 
					        while self.running:
 | 
				
			||||||
 | 
					            effect_cmd = ['tte', random.choice(self.effects)]
 | 
				
			||||||
 | 
					            print(f"$ {' '.join(self.cmd)} | {' '.join(effect_cmd)}")
 | 
				
			||||||
 | 
					            content = subprocess.check_output(self.cmd, env=self.env, stderr=subprocess.DEVNULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            self.proc = subprocess.Popen(effect_cmd, stdin=subprocess.PIPE)
 | 
				
			||||||
 | 
					            self.proc.stdin.write(content)
 | 
				
			||||||
 | 
					            self.proc.stdin.close()
 | 
				
			||||||
 | 
					            self.proc.wait()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self):
 | 
				
			||||||
 | 
					        self.running = False
 | 
				
			||||||
 | 
					        self.proc.terminate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiSaver:
 | 
				
			||||||
 | 
					    savers = [
 | 
				
			||||||
 | 
					        DoomSaver(0),
 | 
				
			||||||
 | 
					        DoomSaver(1),
 | 
				
			||||||
 | 
					        DoomSaver(2),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Screensaver(['cmatrix']),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        TTESaver(['screenfetch', '-N']),
 | 
				
			||||||
 | 
					        TTESaver(['fortune']),
 | 
				
			||||||
 | 
					        TTESaver(['top', '-n1']),
 | 
				
			||||||
 | 
					        TTESaver(['ss', '-nltu']),
 | 
				
			||||||
 | 
					        TTESaver(['ss', '-ntu']),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					    state_filename = 'screensaver.json'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.state_path = os.path.join(f'/run/user/{os.geteuid()}', self.state_filename)
 | 
				
			||||||
 | 
					        self.lock = filelock.FileLock(f'{self.state_path}.lock')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.selected = None
 | 
				
			||||||
 | 
					        self.cleaned_up = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def select(self):
 | 
				
			||||||
 | 
					        assert self.selected is None
 | 
				
			||||||
 | 
					        with self.lock:
 | 
				
			||||||
 | 
					            if not os.path.exists(self.state_path):
 | 
				
			||||||
 | 
					                state = {'instances': []}
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                with open(self.state_path) as f:
 | 
				
			||||||
 | 
					                    state = json.load(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            available = set(range(len(self.savers)))
 | 
				
			||||||
 | 
					            new_instances = []
 | 
				
			||||||
 | 
					            for instance in state['instances']:
 | 
				
			||||||
 | 
					                if not os.path.exists(f"/proc/{instance['pid']}"):
 | 
				
			||||||
 | 
					                    continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                new_instances.append(instance)
 | 
				
			||||||
 | 
					                i = instance['saver']
 | 
				
			||||||
 | 
					                assert i in available
 | 
				
			||||||
 | 
					                available.remove(i)
 | 
				
			||||||
 | 
					            assert available, 'No screensavers left'
 | 
				
			||||||
 | 
					            available = list(available)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            weights = []
 | 
				
			||||||
 | 
					            for i in available:
 | 
				
			||||||
 | 
					                weights.append(self.savers[i].weight)
 | 
				
			||||||
 | 
					            selected_i = random.choices(available, weights=weights)[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            new_instances.append({'pid': os.getpid(), 'saver': selected_i})
 | 
				
			||||||
 | 
					            state['instances'] = new_instances
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            with open(self.state_path, 'w') as f:
 | 
				
			||||||
 | 
					                json.dump(state, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # print(f'Selected saver {selected_i}')
 | 
				
			||||||
 | 
					        self.selected = self.savers[selected_i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def cleanup(self):
 | 
				
			||||||
 | 
					        if self.cleaned_up:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.cleaned_up = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with self.lock:
 | 
				
			||||||
 | 
					            with open(self.state_path) as f:
 | 
				
			||||||
 | 
					                state = json.load(f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for i, instance in enumerate(state['instances']):
 | 
				
			||||||
 | 
					                if instance['pid'] == os.getpid():
 | 
				
			||||||
 | 
					                    del state['instances'][i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            with open(self.state_path, 'w') as f:
 | 
				
			||||||
 | 
					                json.dump(state, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        assert self.selected is not None
 | 
				
			||||||
 | 
					        self.selected.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        signal.signal(signal.SIGINT, self._sighandler)
 | 
				
			||||||
 | 
					        signal.signal(signal.SIGTERM, self._sighandler)
 | 
				
			||||||
 | 
					        signal.signal(signal.SIGHUP, self._sighandler)
 | 
				
			||||||
 | 
					        self.selected.wait()
 | 
				
			||||||
 | 
					        self.cleanup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop(self):
 | 
				
			||||||
 | 
					        assert self.selected is not None
 | 
				
			||||||
 | 
					        print('Shutting down')
 | 
				
			||||||
 | 
					        self.selected.stop()
 | 
				
			||||||
 | 
					        self.cleanup()
 | 
				
			||||||
 | 
					    def _sighandler(self, signum, frame):
 | 
				
			||||||
 | 
					        self.stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    parser = argparse.ArgumentParser(description='Wayland terminal-based lock screen')
 | 
				
			||||||
 | 
					    parser.add_argument('-t', '--terminal', default='alacritty', help='Terminal emulator to use')
 | 
				
			||||||
 | 
					    parser.add_argument('-i', '--instance', action='store_true', help='Run as instance')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    args = parser.parse_args()
 | 
				
			||||||
 | 
					    if not args.instance:
 | 
				
			||||||
 | 
					        subprocess.check_call([
 | 
				
			||||||
 | 
					            'swaylock-plugin', '--command-each',
 | 
				
			||||||
 | 
					            f'@windowtolayer@/bin/windowtolayer -- {args.terminal} -e {sys.argv[0]} --instance'])
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ms = MultiSaver()
 | 
				
			||||||
 | 
					    ms.select()
 | 
				
			||||||
 | 
					    ms.run()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
@@ -12,4 +12,5 @@ in
 | 
				
			|||||||
  chocolate-doom2xx = callPackage ./chocolate-doom2xx { };
 | 
					  chocolate-doom2xx = callPackage ./chocolate-doom2xx { };
 | 
				
			||||||
  windowtolayer = callPackage ./windowtolayer.nix { };
 | 
					  windowtolayer = callPackage ./windowtolayer.nix { };
 | 
				
			||||||
  swaylock-plugin = callPackage ./swaylock-plugin.nix { };
 | 
					  swaylock-plugin = callPackage ./swaylock-plugin.nix { };
 | 
				
			||||||
 | 
					  terminaltexteffects = callPackage ./terminaltexteffects.nix { };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										19
									
								
								pkgs/terminaltexteffects.nix
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								pkgs/terminaltexteffects.nix
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					{ lib
 | 
				
			||||||
 | 
					, python3Packages
 | 
				
			||||||
 | 
					, fetchPypi
 | 
				
			||||||
 | 
					}:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					python3Packages.buildPythonApplication rec {
 | 
				
			||||||
 | 
					  pname = "terminaltexteffects";
 | 
				
			||||||
 | 
					  version = "0.10.1";
 | 
				
			||||||
 | 
					  pyproject = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  src = fetchPypi {
 | 
				
			||||||
 | 
					    inherit pname version;
 | 
				
			||||||
 | 
					    hash = "sha256-NyWPfdgLeXAxKPJOzB7j4aT+zjrURN59CGcv0Vt99y0=";
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  build-system = with python3Packages; [
 | 
				
			||||||
 | 
					    poetry-core
 | 
				
			||||||
 | 
					  ];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user