feat(greetd): use astal instead of ags
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-03-24 13:54:33 -04:00
parent 9bceac68cd
commit 3f0d4bb691
12 changed files with 153 additions and 191 deletions

View file

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

View file

@ -29,19 +29,19 @@ export const transpileTypeScript = async(host) => {
// Create the dir if it doesn't exist
`mkdir -p /tmp/astal-${host}; ` +
// Let bun see tsconfig.json
`cd ${App.configDir};` +
`bun build ${App.configDir}/${host}.ts ` +
'--external resource:///* ' +
'--external gi://* ' +
'--external cairo ' +
'--external */fzf.es.js ' +
// Since bun wants to right in cwd, we just redirect stdin instead
// Since bun wants to write in cwd, we just redirect stdin instead
`> ${outPath}`,
]).catch(print);
if (host !== 'greeter') {
watchAndCompileSass(host);
}
return await import(`file://${outPath}`);
};

View file

@ -0,0 +1,16 @@
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,10 +0,0 @@
window {
all: unset;
}
.base {
background-color: #{"@window_bg_color"};
border: 1px solid #{"@accent_bg_color"};
padding: 5px;
}

View file

@ -0,0 +1,115 @@
const { Box, Entry, Label, Window } = Widget;
const { execAsync, idle, readFileAsync } = Utils;
const greetd = await Service.import('greetd');
const { Gtk } = imports.gi;
const DEFAULT_NAME = 'matt';
// Types
import { StringObject } from 'types/@girs/gtk-4.0/gtk-4.0.cjs';
// Run Wallpaper daemon here to not cause issues at startup
execAsync(['bash', '-c',
`swww init --no-cache && swww img -t none ${App.configDir}/.wallpaper`]).catch(print);
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 = Gtk.DropDown.new_from_strings(users.map((u) => u.name));
const password = Entry({
placeholderText: 'Password',
visibility: false,
setup: (self) => idle(() => {
self.grab_focus();
}),
on_accept: () => {
greetd.login(
(dropdown.selectedItem as StringObject)['string'] || '',
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,
cssClasses: ['base'],
children: [
Box({
vertical: true,
hpack: 'center',
vpack: 'center',
hexpand: true,
vexpand: true,
setup: (self) => {
self.add_css_class('linked');
idle(() => {
const usernames = [] as string[];
for (let i = 0; i < dropdown.model.get_n_items(); ++i) {
const name = (dropdown.model.get_item(i) as StringObject)['string'];
if (name) {
usernames.push(name);
}
}
if (usernames.includes(DEFAULT_NAME)) {
dropdown.set_selected(usernames.indexOf(DEFAULT_NAME));
}
});
},
children: [
dropdown,
password,
],
}),
response,
],
}),
});

View file

@ -1,20 +0,0 @@
import Adw from 'gi://Adw';
App.config({
windows: () => [
Widget.Window({
name: 'test',
child: Widget.Box({
setup: (self) => {
self.toggleCssClass('base');
},
child: new Adw.SplitButton({
label: 'test',
}),
}),
}),
],
});

View file

@ -1,140 +0,0 @@
/* eslint no-magic-numbers: 0 */
const { Box, Button, Entry, Label, Menu, MenuItem, Window } = Widget;
const { execAsync, idle, readFileAsync } = Utils;
const greetd = await Service.import('greetd');
const { Gdk } = imports.gi;
const DEFAULT_NAME = 'matt';
// Types
type User = {
name: string;
uid: number;
gid: number;
desc: string;
home: string;
shell: string;
};
// Run Wallpaper daemon here to not cause issues at startup
execAsync(['swww', 'init', '--no-cache']).then(() => {
execAsync([
'swww', 'img', '-t', 'none',
`${App.configDir}/.wallpaper`,
]).catch(print);
}).catch(print);
// Put ref of Label here to change it easily later
const name = Label(DEFAULT_NAME);
// Initiate menu here to not have garbage collection take it away
// TODO: figure out type
let menu;
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';
});
};
// FIXME: make menu scrollable
const DropdownMenu = (users: User[]) => Menu({
attach_widget: dropdown,
children: users.map((u) => MenuItem({
on_activate: () => {
name.label = u.name;
},
child: Label({
label: u.name,
justification: 'center',
css: `min-width: ${dropdown.get_allocated_width() / 2}px;`,
}),
})),
});
const dropdown = Button({
child: name,
setup: () => {
idle(() => {
readFileAsync('/etc/passwd').then((out) => {
const users = parsePasswd(out);
menu = DropdownMenu(users);
}).catch(print);
});
},
on_primary_click_release: (self, event) => {
menu.popup_at_widget(
self,
Gdk.Gravity.SOUTH,
Gdk.Gravity.NORTH,
event,
);
},
});
const password = Entry({
placeholder_text: 'Password',
visibility: false,
on_accept: () => {
greetd.login(
name.label || '',
password.text || '',
'Hyprland',
).catch((error) => {
response.label = JSON.stringify(error);
});
},
}).on('realize', (entry) => entry.grab_focus());
const response = Label();
const win = Window({
name: 'greeter',
css: 'background-color: transparent;',
anchor: ['top', 'left', 'right', 'bottom'],
keymode: 'on-demand',
child: Box({
vertical: true,
hpack: 'center',
vpack: 'center',
hexpand: true,
vexpand: true,
children: [
dropdown,
password,
response,
],
}),
});
export default { windows: [win] };

View file

@ -41,9 +41,7 @@ export const transpileTypeScript = async(host) => {
`> ${outPath}`,
]).catch(print);
if (host !== 'greeter') {
watchAndCompileSass(host);
}
return await import(`file://${outPath}`);
};

View file

@ -1,4 +0,0 @@
// Delete /tmp/ags-greeter before and after using this
import { transpileTypeScript } from './js/utils.js';
export default (await transpileTypeScript('greeter')).default;

View file

@ -1,5 +1,5 @@
{
ags,
astal,
config,
pkgs,
...
@ -15,12 +15,12 @@ in {
home-manager.users.greeter = {
imports = [
ags.homeManagerModules.default
astal.homeManagerModules.default
../../common/vars
../../home/theme
];
programs.ags.enable = true;
programs.astal.enable = true;
home = {
packages = [
@ -33,14 +33,14 @@ in {
];
file = {
".config/ags/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png";
".config/astal/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png";
".config/ags" = {
source = ../ags/config;
".config/astal" = {
source = ../ags/astal;
recursive = true;
};
".config/ags/config.js".text =
".config/astal/config.js".text =
/*
javascript
*/

View file

@ -11,7 +11,7 @@
isTouchscreen = config.hardware.sensor.iio.enable;
hyprland = config.home-manager.users.${mainUser}.wayland.windowManager.hyprland.finalPackage;
in {
imports = [./ags.nix];
imports = [./astal.nix];
services = {
xserver = {

View file

@ -93,7 +93,7 @@ in {
}
exec-once = ${setupMonitors}
exec-once = ags -b greeter &> /tmp/ags.log; hyprctl dispatch exit
exec-once = astal -b greeter &> /tmp/astal.log; hyprctl dispatch exit
''
);
}