feat(desktop): move greetd to agsV2
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
44bd294bf0
commit
bb6db96f23
16 changed files with 270 additions and 252 deletions
|
@ -2,7 +2,6 @@
|
||||||
// TODO: quick-settings
|
// TODO: quick-settings
|
||||||
// TODO: music player stuff
|
// TODO: music player stuff
|
||||||
// TODO: on-screen-keyboard
|
// TODO: on-screen-keyboard
|
||||||
// TODO: Greetd
|
|
||||||
// TODO: GSR
|
// TODO: GSR
|
||||||
|
|
||||||
import GLib from 'gi://GLib';
|
import GLib from 'gi://GLib';
|
||||||
|
|
20
nixosModules/ags-v2/config/configurations/greeter.ts
Normal file
20
nixosModules/ags-v2/config/configurations/greeter.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
export default async() => {
|
||||||
|
const { execAsync } = await import('astal');
|
||||||
|
const { App } = await import('astal/gtk3');
|
||||||
|
|
||||||
|
const Greeter = (await import('../widgets/greeter/main')).default;
|
||||||
|
|
||||||
|
const style = (await import('../style/greeter.scss')).default;
|
||||||
|
|
||||||
|
|
||||||
|
App.start({
|
||||||
|
css: style,
|
||||||
|
instanceName: 'greeter',
|
||||||
|
|
||||||
|
main: () => {
|
||||||
|
execAsync('hyprpaper').catch(() => { /**/ });
|
||||||
|
|
||||||
|
Greeter();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
18
nixosModules/ags-v2/config/style/greeter.scss
Normal file
18
nixosModules/ags-v2/config/style/greeter.scss
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
@use 'colors';
|
||||||
|
|
||||||
|
window {
|
||||||
|
all: unset;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.base {
|
||||||
|
background-color: colors.$window_bg_color;
|
||||||
|
border: 1.3px solid colors.$accent_bg_color;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
dropdown popover.menu {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
118
nixosModules/ags-v2/config/widgets/greeter/main.tsx
Normal file
118
nixosModules/ags-v2/config/widgets/greeter/main.tsx
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
import { idle, readFile } from 'astal';
|
||||||
|
import { Astal, Gtk, Widget } from 'astal/gtk3';
|
||||||
|
|
||||||
|
import AstalGreet from 'gi://AstalGreet';
|
||||||
|
|
||||||
|
|
||||||
|
const DEFAULT_NAME = 'matt';
|
||||||
|
const PARSED_INDEX = {
|
||||||
|
name: 0,
|
||||||
|
uid: 2,
|
||||||
|
gid: 3,
|
||||||
|
desc: 4,
|
||||||
|
home: 5,
|
||||||
|
shell: 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsePasswd = (fileContent: string) => {
|
||||||
|
const splitUsers = fileContent.split('\n');
|
||||||
|
const parsedUsers = splitUsers.map((u) => {
|
||||||
|
const user = u.split(':');
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: user[PARSED_INDEX.name],
|
||||||
|
uid: Number(user[PARSED_INDEX.uid]),
|
||||||
|
gid: Number(user[PARSED_INDEX.gid]),
|
||||||
|
desc: user[PARSED_INDEX.desc],
|
||||||
|
home: user[PARSED_INDEX.home],
|
||||||
|
shell: user[PARSED_INDEX.shell],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter out system users, nixbld users and nobody
|
||||||
|
return parsedUsers.filter((u) => {
|
||||||
|
return u.uid >= 1000 &&
|
||||||
|
!u.name.includes('nixbld') &&
|
||||||
|
u.name !== 'nobody';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const users = parsePasswd(readFile('/etc/passwd'));
|
||||||
|
|
||||||
|
const dropdown = new Gtk.ComboBoxText();
|
||||||
|
|
||||||
|
dropdown.show_all();
|
||||||
|
|
||||||
|
users.forEach((u) => {
|
||||||
|
dropdown.append(null, u.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
const response = <label /> as Widget.Label;
|
||||||
|
|
||||||
|
const password = (
|
||||||
|
<entry
|
||||||
|
placeholderText="Password"
|
||||||
|
visibility={false}
|
||||||
|
|
||||||
|
setup={(self) => idle(() => {
|
||||||
|
self.grab_focus();
|
||||||
|
})}
|
||||||
|
|
||||||
|
onActivate={(self) => {
|
||||||
|
AstalGreet.login(
|
||||||
|
dropdown.get_active_text() ?? '',
|
||||||
|
self.text || '',
|
||||||
|
'Hyprland',
|
||||||
|
(_, res) => {
|
||||||
|
try {
|
||||||
|
AstalGreet.login_finish(res);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
response.label = JSON.stringify(error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
export default () => (
|
||||||
|
<window
|
||||||
|
name="greeter"
|
||||||
|
keymode={Astal.Keymode.ON_DEMAND}
|
||||||
|
>
|
||||||
|
<box
|
||||||
|
vertical
|
||||||
|
halign={Gtk.Align.CENTER}
|
||||||
|
valign={Gtk.Align.CENTER}
|
||||||
|
hexpand
|
||||||
|
vexpand
|
||||||
|
className="base"
|
||||||
|
>
|
||||||
|
<box
|
||||||
|
vertical
|
||||||
|
halign={Gtk.Align.CENTER}
|
||||||
|
valign={Gtk.Align.CENTER}
|
||||||
|
hexpand
|
||||||
|
vexpand
|
||||||
|
className="linked"
|
||||||
|
|
||||||
|
setup={() => {
|
||||||
|
idle(() => {
|
||||||
|
const usernames = users.map((u) => u.name);
|
||||||
|
|
||||||
|
if (usernames.includes(DEFAULT_NAME)) {
|
||||||
|
dropdown.set_active(usernames.indexOf(DEFAULT_NAME));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{dropdown}
|
||||||
|
{password}
|
||||||
|
</box>
|
||||||
|
|
||||||
|
{response}
|
||||||
|
</box>
|
||||||
|
</window>
|
||||||
|
);
|
112
nixosModules/desktop/manager/ags.nix
Normal file
112
nixosModules/desktop/manager/ags.nix
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
self: {
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}: let
|
||||||
|
# TODO: clean this up
|
||||||
|
inherit (self.inputs) agsV2 gtk-session-lock;
|
||||||
|
in {
|
||||||
|
config = let
|
||||||
|
# Libs
|
||||||
|
inherit (lib) attrValues boolToString removeAttrs;
|
||||||
|
|
||||||
|
# Cfg info
|
||||||
|
inherit (config.networking) hostName;
|
||||||
|
cfgDesktop = config.roles.desktop;
|
||||||
|
|
||||||
|
# Astal libraries
|
||||||
|
gtkSessionLock = gtk-session-lock.packages.${pkgs.system}.default;
|
||||||
|
agsV2Packages = agsV2.packages.${pkgs.system};
|
||||||
|
astalLibs = attrValues (removeAttrs agsV2.inputs.astal.packages.${pkgs.system} ["docs" "gjs"]) ++ [gtkSessionLock];
|
||||||
|
|
||||||
|
# Final ags package
|
||||||
|
agsFull = agsV2Packages.ags.override {extraPackages = astalLibs;};
|
||||||
|
|
||||||
|
agsConfig = let
|
||||||
|
tsconfig = pkgs.writers.writeJSON "tsconfig.json" {
|
||||||
|
"$schema" = "https://json.schemastore.org/tsconfig";
|
||||||
|
"compilerOptions" = {
|
||||||
|
"experimentalDecorators" = true;
|
||||||
|
"strict" = true;
|
||||||
|
"target" = "ES2023";
|
||||||
|
"moduleResolution" = "Bundler";
|
||||||
|
"jsx" = "react-jsx";
|
||||||
|
"jsxImportSource" = "${agsV2Packages.gjs}/share/astal/gjs/gtk3";
|
||||||
|
"paths" = {
|
||||||
|
"astal" = ["${agsV2Packages.gjs}/share/astal/gjs"];
|
||||||
|
"astal/*" = ["${agsV2Packages.gjs}/share/astal/gjs/*"];
|
||||||
|
};
|
||||||
|
"skipLibCheck" = true;
|
||||||
|
"module" = "ES2022";
|
||||||
|
"lib" = ["ES2023"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
varsTs =
|
||||||
|
pkgs.writeText "vars.ts"
|
||||||
|
# javascript
|
||||||
|
''
|
||||||
|
export default {
|
||||||
|
mainMonitor: '${cfgDesktop.mainMonitor}',
|
||||||
|
dupeLockscreen: ${boolToString cfgDesktop.displayManager.duplicateScreen},
|
||||||
|
hasFprintd: ${boolToString (hostName == "wim")},
|
||||||
|
};
|
||||||
|
'';
|
||||||
|
|
||||||
|
flakeDir = config.environment.variables.FLAKE;
|
||||||
|
modulesDir = "${lib.removePrefix "/home/${cfg.user}/" flakeDir}/nixosModules";
|
||||||
|
nodeModules = config.home-manager.users.${cfg.user}.home.file."${modulesDir}/ags/config/node_modules".source
|
||||||
|
or config.home-manager.users.${cfg.user}.home.file."${modulesDir}/ags-v2/config/node_modules".source;
|
||||||
|
in
|
||||||
|
pkgs.runCommandLocal "agsConfig" {} ''
|
||||||
|
cp -ar ${tsconfig} ./tsconfig.json
|
||||||
|
cp -ar ${../../../ags-v2/config}/* ./.
|
||||||
|
chmod +w -R ./.
|
||||||
|
cp -ar ${varsTs} ./widgets/lockscreen/vars.ts
|
||||||
|
cp -ar ${nodeModules} ./node_modules
|
||||||
|
${agsFull}/bin/ags bundle ./app.ts $out
|
||||||
|
'';
|
||||||
|
|
||||||
|
cfg = config.roles.desktop;
|
||||||
|
|
||||||
|
hyprland =
|
||||||
|
config
|
||||||
|
.home-manager
|
||||||
|
.users
|
||||||
|
.${cfg.user}
|
||||||
|
.wayland
|
||||||
|
.windowManager
|
||||||
|
.hyprland
|
||||||
|
.finalPackage;
|
||||||
|
in {
|
||||||
|
# Add home folder for home-manager to work
|
||||||
|
users.users.greeter = {
|
||||||
|
home = "/var/lib/greeter";
|
||||||
|
createHome = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
home-manager.users.greeter = {
|
||||||
|
home.packages = [
|
||||||
|
hyprland
|
||||||
|
|
||||||
|
(pkgs.writeShellApplication {
|
||||||
|
name = "agsGreeter";
|
||||||
|
|
||||||
|
runtimeInputs = [
|
||||||
|
agsFull
|
||||||
|
hyprland
|
||||||
|
];
|
||||||
|
|
||||||
|
text = ''
|
||||||
|
export CONF="greeter"
|
||||||
|
exec ags run ${agsConfig}
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# For accurate stack trace
|
||||||
|
_file = ./default.nix;
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
../../../ags/config/.envrc
|
|
|
@ -1,90 +0,0 @@
|
||||||
self: {
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
inherit (self.inputs) ags;
|
|
||||||
in {
|
|
||||||
config = let
|
|
||||||
cfg = config.roles.desktop;
|
|
||||||
|
|
||||||
hyprland =
|
|
||||||
config
|
|
||||||
.home-manager
|
|
||||||
.users
|
|
||||||
.${cfg.user}
|
|
||||||
.wayland
|
|
||||||
.windowManager
|
|
||||||
.hyprland
|
|
||||||
.finalPackage;
|
|
||||||
in {
|
|
||||||
# Add home folder for home-manager to work
|
|
||||||
users.users.greeter = {
|
|
||||||
home = "/var/lib/greeter";
|
|
||||||
createHome = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Setup node modules for dev env
|
|
||||||
home-manager.users.${cfg.user}.home.file = let
|
|
||||||
flakeDir = config.environment.variables.FLAKE;
|
|
||||||
modulesDir = "${lib.removePrefix "/home/${cfg.user}/" flakeDir}/nixosModules";
|
|
||||||
nodeModules =
|
|
||||||
config.home-manager.users.${cfg.user}.home.file."${modulesDir}/ags/config/node_modules".source
|
|
||||||
or config.home-manager.users.${cfg.user}.home.file."${modulesDir}/ags-v2/config/node_modules".source;
|
|
||||||
in {
|
|
||||||
"${modulesDir}/desktop/manager/ags/node_modules".source = nodeModules;
|
|
||||||
};
|
|
||||||
|
|
||||||
home-manager.users.greeter = {
|
|
||||||
imports = [ags.homeManagerModules.default];
|
|
||||||
|
|
||||||
programs.ags.enable = true;
|
|
||||||
|
|
||||||
home.packages = [
|
|
||||||
hyprland
|
|
||||||
pkgs.gtk3
|
|
||||||
pkgs.glib
|
|
||||||
];
|
|
||||||
|
|
||||||
xdg.configFile = {
|
|
||||||
"ags".source = pkgs.stdenv.mkDerivation {
|
|
||||||
name = "ags-greeter";
|
|
||||||
src = lib.fileset.toSource {
|
|
||||||
root = ./.;
|
|
||||||
fileset = lib.fileset.unions [
|
|
||||||
./scss
|
|
||||||
./greeter.ts
|
|
||||||
./ts
|
|
||||||
./tsconfig.json
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
buildInputs = builtins.attrValues {
|
|
||||||
inherit
|
|
||||||
(pkgs)
|
|
||||||
bun
|
|
||||||
dart-sass
|
|
||||||
;
|
|
||||||
};
|
|
||||||
|
|
||||||
buildPhase = ''
|
|
||||||
sass ./scss/greeter.scss style.css
|
|
||||||
bun build ./greeter.ts \
|
|
||||||
--external resource:///* \
|
|
||||||
--external gi://* \
|
|
||||||
--external cairo > config.js
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
mv style.css config.js $out/
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
# For accurate stack trace
|
|
||||||
_file = ./default.nix;
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
../../../ags/config/eslint.config.ts
|
|
|
@ -1,11 +0,0 @@
|
||||||
Utils.execAsync('hyprpaper');
|
|
||||||
|
|
||||||
import Greeter from './ts/greetd/main.ts';
|
|
||||||
|
|
||||||
App.config({
|
|
||||||
style: './style.css',
|
|
||||||
|
|
||||||
windows: () => [
|
|
||||||
Greeter(),
|
|
||||||
],
|
|
||||||
});
|
|
|
@ -1 +0,0 @@
|
||||||
../../../ags/config/package-lock.json
|
|
|
@ -1 +0,0 @@
|
||||||
../../../ags/config/package.json
|
|
|
@ -1,16 +0,0 @@
|
||||||
window {
|
|
||||||
all: unset;
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.base {
|
|
||||||
background-color: #{"@window_bg_color"};
|
|
||||||
border: 1.3px solid #{"@accent_bg_color"};
|
|
||||||
border-radius: 12px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
dropdown popover.menu {
|
|
||||||
padding-top: 0;
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
const { Box, Entry, Label, Window } = Widget;
|
|
||||||
const { idle, readFileAsync } = Utils;
|
|
||||||
|
|
||||||
const greetd = await Service.import('greetd');
|
|
||||||
|
|
||||||
const { Gtk } = imports.gi;
|
|
||||||
|
|
||||||
const DEFAULT_NAME = 'matt';
|
|
||||||
|
|
||||||
|
|
||||||
const parsePasswd = (fileContent: string) => {
|
|
||||||
const splitUsers = fileContent.split('\n');
|
|
||||||
const parsedUsers = splitUsers.map((u) => {
|
|
||||||
const user = u.split(':');
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: user[0],
|
|
||||||
uid: Number(user[2]),
|
|
||||||
gid: Number(user[3]),
|
|
||||||
desc: user[4],
|
|
||||||
home: user[5],
|
|
||||||
shell: user[6],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Filter out system users, nixbld users and nobody
|
|
||||||
return parsedUsers.filter((u) => {
|
|
||||||
return u.uid >= 1000 &&
|
|
||||||
!u.name.includes('nixbld') &&
|
|
||||||
u.name !== 'nobody';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const users = parsePasswd(await readFileAsync('/etc/passwd'));
|
|
||||||
|
|
||||||
const dropdown = new Gtk.ComboBoxText();
|
|
||||||
|
|
||||||
users.forEach((u) => {
|
|
||||||
dropdown.append(null, u.name);
|
|
||||||
});
|
|
||||||
|
|
||||||
const password = Entry({
|
|
||||||
placeholderText: 'Password',
|
|
||||||
visibility: false,
|
|
||||||
|
|
||||||
setup: (self) => idle(() => {
|
|
||||||
self.grab_focus();
|
|
||||||
}),
|
|
||||||
|
|
||||||
on_accept: () => {
|
|
||||||
greetd.login(
|
|
||||||
dropdown.get_active_text() ?? '',
|
|
||||||
password.text || '',
|
|
||||||
'Hyprland',
|
|
||||||
|
|
||||||
).catch((error) => {
|
|
||||||
response.label = JSON.stringify(error);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = Label();
|
|
||||||
|
|
||||||
export default () => Window({
|
|
||||||
name: 'greeter',
|
|
||||||
keymode: 'on-demand',
|
|
||||||
|
|
||||||
child: Box({
|
|
||||||
vertical: true,
|
|
||||||
hpack: 'center',
|
|
||||||
vpack: 'center',
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: true,
|
|
||||||
class_names: ['base'],
|
|
||||||
|
|
||||||
children: [
|
|
||||||
Box({
|
|
||||||
vertical: true,
|
|
||||||
hpack: 'center',
|
|
||||||
vpack: 'center',
|
|
||||||
hexpand: true,
|
|
||||||
vexpand: true,
|
|
||||||
class_names: ['linked'],
|
|
||||||
|
|
||||||
setup: () => {
|
|
||||||
idle(() => {
|
|
||||||
const usernames = users.map((u) => u.name);
|
|
||||||
|
|
||||||
if (usernames.includes(DEFAULT_NAME)) {
|
|
||||||
dropdown.set_active(usernames.indexOf(DEFAULT_NAME));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
children: [
|
|
||||||
dropdown,
|
|
||||||
password,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
response,
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "ES2022",
|
|
||||||
"module": "ES2022",
|
|
||||||
"lib": ["ES2022"],
|
|
||||||
"noEmit": true,
|
|
||||||
"allowImportingTsExtensions": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"allowJs": true,
|
|
||||||
"checkJs": true,
|
|
||||||
"strict": true,
|
|
||||||
"noImplicitAny": false,
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"fzf": ["./node_modules/fzf/dist/types"]
|
|
||||||
},
|
|
||||||
"typeRoots": [
|
|
||||||
"./types",
|
|
||||||
"./global-types.d.ts",
|
|
||||||
"./node_modules"
|
|
||||||
],
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"forceConsistentCasingInFileNames": true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ self: {
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
imports = [
|
imports = [
|
||||||
(import ./ags self)
|
(import ./ags.nix self)
|
||||||
(import ./hyprland.nix self)
|
(import ./hyprland.nix self)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ self: {
|
||||||
|
|
||||||
exec-once = [
|
exec-once = [
|
||||||
setupMonitors
|
setupMonitors
|
||||||
"ags -b greeter &> /tmp/ags-greetd.log; hyprctl dispatch exit"
|
"agsGreeter &> /tmp/ags-greetd.log; hyprctl dispatch exit"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
// devices;
|
// devices;
|
||||||
|
|
Loading…
Reference in a new issue