feat(desktop): move greetd to agsV2
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-11-11 20:33:44 -05:00
parent 44bd294bf0
commit bfaaed6924
16 changed files with 270 additions and 252 deletions

View file

@ -2,7 +2,6 @@
// TODO: quick-settings
// TODO: music player stuff
// TODO: on-screen-keyboard
// TODO: Greetd
// TODO: GSR
import GLib from 'gi://GLib';

View 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();
},
});
};

View 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;
}

View 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>
);

View 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;
}

View file

@ -1 +0,0 @@
../../../ags/config/.envrc

View file

@ -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;
}

View file

@ -1 +0,0 @@
../../../ags/config/eslint.config.ts

View file

@ -1,11 +0,0 @@
Utils.execAsync('hyprpaper');
import Greeter from './ts/greetd/main.ts';
App.config({
style: './style.css',
windows: () => [
Greeter(),
],
});

View file

@ -1 +0,0 @@
../../../ags/config/package-lock.json

View file

@ -1 +0,0 @@
../../../ags/config/package.json

View file

@ -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;
}

View file

@ -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,
],
}),
});

View file

@ -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
}
}

View file

@ -4,7 +4,7 @@ self: {
...
}: {
imports = [
(import ./ags self)
(import ./ags.nix self)
(import ./hyprland.nix self)
];

View file

@ -54,7 +54,7 @@ self: {
exec-once = [
setupMonitors
"ags -b greeter &> /tmp/ags-greetd.log; hyprctl dispatch exit"
"agsGreeter &> /tmp/ags-greetd.log; hyprctl dispatch exit"
];
}
// devices;