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
b49bcf7cc2
15 changed files with 269 additions and 251 deletions
|
@ -2,7 +2,6 @@
|
|||
// TODO: quick-settings
|
||||
// TODO: music player stuff
|
||||
// TODO: on-screen-keyboard
|
||||
// TODO: Greetd
|
||||
// TODO: GSR
|
||||
|
||||
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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue