feat(greetd): use astal instead of ags
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
9bceac68cd
commit
3f0d4bb691
12 changed files with 153 additions and 191 deletions
7
modules/ags/astal/greeter.ts
Normal file
7
modules/ags/astal/greeter.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Greeter from './ts/greetd/main';
|
||||||
|
|
||||||
|
App.config({
|
||||||
|
windows: () => [
|
||||||
|
Greeter(),
|
||||||
|
],
|
||||||
|
});
|
|
@ -29,19 +29,19 @@ export const transpileTypeScript = async(host) => {
|
||||||
// Create the dir if it doesn't exist
|
// Create the dir if it doesn't exist
|
||||||
`mkdir -p /tmp/astal-${host}; ` +
|
`mkdir -p /tmp/astal-${host}; ` +
|
||||||
|
|
||||||
|
// Let bun see tsconfig.json
|
||||||
|
`cd ${App.configDir};` +
|
||||||
|
|
||||||
`bun build ${App.configDir}/${host}.ts ` +
|
`bun build ${App.configDir}/${host}.ts ` +
|
||||||
'--external resource:///* ' +
|
'--external resource:///* ' +
|
||||||
'--external gi://* ' +
|
'--external gi://* ' +
|
||||||
'--external cairo ' +
|
'--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}`,
|
`> ${outPath}`,
|
||||||
]).catch(print);
|
]).catch(print);
|
||||||
|
|
||||||
if (host !== 'greeter') {
|
watchAndCompileSass(host);
|
||||||
watchAndCompileSass(host);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await import(`file://${outPath}`);
|
return await import(`file://${outPath}`);
|
||||||
};
|
};
|
||||||
|
|
16
modules/ags/astal/scss/greeter.scss
Normal file
16
modules/ags/astal/scss/greeter.scss
Normal 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;
|
||||||
|
}
|
|
@ -1,10 +0,0 @@
|
||||||
window {
|
|
||||||
all: unset;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.base {
|
|
||||||
background-color: #{"@window_bg_color"};
|
|
||||||
border: 1px solid #{"@accent_bg_color"};
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
115
modules/ags/astal/ts/greetd/main.ts
Normal file
115
modules/ags/astal/ts/greetd/main.ts
Normal 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,
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
});
|
|
@ -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',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
|
@ -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] };
|
|
|
@ -41,9 +41,7 @@ export const transpileTypeScript = async(host) => {
|
||||||
`> ${outPath}`,
|
`> ${outPath}`,
|
||||||
]).catch(print);
|
]).catch(print);
|
||||||
|
|
||||||
if (host !== 'greeter') {
|
watchAndCompileSass(host);
|
||||||
watchAndCompileSass(host);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await import(`file://${outPath}`);
|
return await import(`file://${outPath}`);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
ags,
|
astal,
|
||||||
config,
|
config,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
|
@ -15,12 +15,12 @@ in {
|
||||||
|
|
||||||
home-manager.users.greeter = {
|
home-manager.users.greeter = {
|
||||||
imports = [
|
imports = [
|
||||||
ags.homeManagerModules.default
|
astal.homeManagerModules.default
|
||||||
../../common/vars
|
../../common/vars
|
||||||
../../home/theme
|
../../home/theme
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.ags.enable = true;
|
programs.astal.enable = true;
|
||||||
|
|
||||||
home = {
|
home = {
|
||||||
packages = [
|
packages = [
|
||||||
|
@ -33,14 +33,14 @@ in {
|
||||||
];
|
];
|
||||||
|
|
||||||
file = {
|
file = {
|
||||||
".config/ags/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png";
|
".config/astal/.wallpaper".source = "${pkgs.dracula-theme}/wallpapers/waves.png";
|
||||||
|
|
||||||
".config/ags" = {
|
".config/astal" = {
|
||||||
source = ../ags/config;
|
source = ../ags/astal;
|
||||||
recursive = true;
|
recursive = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
".config/ags/config.js".text =
|
".config/astal/config.js".text =
|
||||||
/*
|
/*
|
||||||
javascript
|
javascript
|
||||||
*/
|
*/
|
|
@ -11,7 +11,7 @@
|
||||||
isTouchscreen = config.hardware.sensor.iio.enable;
|
isTouchscreen = config.hardware.sensor.iio.enable;
|
||||||
hyprland = config.home-manager.users.${mainUser}.wayland.windowManager.hyprland.finalPackage;
|
hyprland = config.home-manager.users.${mainUser}.wayland.windowManager.hyprland.finalPackage;
|
||||||
in {
|
in {
|
||||||
imports = [./ags.nix];
|
imports = [./astal.nix];
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
xserver = {
|
xserver = {
|
||||||
|
|
|
@ -93,7 +93,7 @@ in {
|
||||||
}
|
}
|
||||||
|
|
||||||
exec-once = ${setupMonitors}
|
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
|
||||||
''
|
''
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue