140 lines
3.1 KiB
TypeScript
140 lines
3.1 KiB
TypeScript
/* 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] };
|