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
|
||||
`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);
|
||||
}
|
||||
watchAndCompileSass(host);
|
||||
|
||||
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}`,
|
||||
]).catch(print);
|
||||
|
||||
if (host !== 'greeter') {
|
||||
watchAndCompileSass(host);
|
||||
}
|
||||
watchAndCompileSass(host);
|
||||
|
||||
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,
|
||||
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
|
||||
*/
|
|
@ -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 = {
|
||||
|
|
|
@ -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
|
||||
''
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue