feat(agsV2): add lockscreen
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-22 00:14:39 -04:00
parent 9f764bf21b
commit e03d34d75b
7 changed files with 316 additions and 20 deletions

2
.gitignore vendored
View file

@ -13,7 +13,7 @@ result*
.nixd.json
## AGS
nixosModules/ags/config/ts/lockscreen/vars.ts
**/vars.ts
**/config.js
*icons
**/types

View file

@ -21,6 +21,7 @@ in {
mkIf cfgDesktop.ags.enable {
# Enable pam for ags
security.pam.services.ags = {};
security.pam.services.astal-auth = {};
services.upower.enable = true;

View file

@ -1,5 +1,7 @@
import { App } from 'astal/gtk3';
import GLib from 'gi://GLib?version=2.0';
import style from './style.scss';
import AppLauncher from './widgets/applauncher/main';
@ -13,7 +15,26 @@ import PowerMenu from './widgets/powermenu/main';
import MonitorClicks from './services/monitor-clicks';
import Lockscreen from './widgets/lockscreen/main';
const CONF = GLib.getenv('CONF');
switch (CONF) {
case 'lock': {
App.start({
css: style,
instanceName: CONF,
main: () => {
Lockscreen();
},
});
break;
}
case 'wim': {
App.start({
css: style,
@ -31,3 +52,7 @@ App.start({
new MonitorClicks();
},
});
break;
}
}

View file

@ -1,15 +1,22 @@
self: {
lib,
osConfig,
pkgs,
...
}: {
config = let
inherit (lib) attrValues removeAttrs;
inherit (lib) attrValues boolToString removeAttrs;
inherit (self.inputs) agsV2;
inherit (osConfig.vars) hostName;
cfgDesktop = osConfig.roles.desktop;
inherit (self.inputs) agsV2 gtk-session-lock;
gtkSessionLock = gtk-session-lock.packages.${pkgs.system}.default;
agsV2Packages = agsV2.packages.${pkgs.system};
astalLibs = attrValues (removeAttrs agsV2.inputs.astal.packages.${pkgs.system} ["docs" "gjs"]);
astalLibs = attrValues (removeAttrs agsV2.inputs.astal.packages.${pkgs.system} ["docs" "gjs"]) ++ [gtkSessionLock];
agsFull = agsV2Packages.ags.override {extraPackages = astalLibs;};
configDir = "/home/matt/.nix/nixosModules/ags/v2";
in {
home = {
@ -17,7 +24,15 @@ self: {
(pkgs.writeShellApplication {
name = "agsV2";
text = ''
exec ${agsV2Packages.agsFull}/bin/ags --config ${configDir} "$@"
export CONF="wim"
exec ${agsFull}/bin/ags --config ${configDir} "$@"
'';
})
(pkgs.writeShellApplication {
name = "agsConf";
text = ''
export CONF="$1"
exec ${agsFull}/bin/ags --config ${configDir}
'';
})
];
@ -56,6 +71,16 @@ self: {
"lib" = ["ES2023"];
};
};
"${configDir}/widgets/lockscreen/vars.ts".text =
# javascript
''
export default {
mainMonitor: '${cfgDesktop.mainMonitor}',
dupeLockscreen: ${boolToString cfgDesktop.displayManager.duplicateScreen},
hasFprintd: ${boolToString (hostName == "wim")},
};
'';
}
);
};

View file

@ -16,5 +16,6 @@ window, viewport {
@import 'widgets/bar/style.scss';
@import 'widgets/date/style.scss';
@import 'widgets/icon-browser/style.scss';
@import 'widgets/lockscreen/style.scss';
@import 'widgets/notifs/style.scss';
@import 'widgets/powermenu/style.scss';

View file

@ -0,0 +1,240 @@
import { bind, idle, timeout, Variable } from 'astal';
import { App, Astal, Gdk, Gtk, Widget } from 'astal/gtk3';
import { register } from 'astal/gobject';
import AstalAuth from 'gi://AstalAuth';
import Lock from 'gi://GtkSessionLock?version=0.1';
import Separator from '../misc/separator';
import { get_hyprland_monitor_desc } from '../../lib';
declare global {
function authFinger(): void;
}
// This file is generated by Nix
import Vars from './vars';
export default () => {
const lock = Lock.prepare_lock();
const windows = new Map<Gdk.Monitor, Gtk.Window>();
@register()
class BlurredBox extends Widget.Box {
geometry = {} as { w: number, h: number };
}
const blurBGs: BlurredBox[] = [];
const transition_duration = 1000;
const WINDOW_MARGINS = -2;
const ENTRY_SPACING = 20;
const CLOCK_SPACING = 60;
const bgCSS = ({ w = 1, h = 1 } = {}) => `
border: 2px solid rgba(189, 147, 249, 0.8);
background: rgba(0, 0, 0, 0.2);
min-height: ${h}px;
min-width: ${w}px;
transition: min-height ${transition_duration / 2}ms,
min-width ${transition_duration / 2}ms;
`;
const unlock = () => {
blurBGs.forEach((b) => {
b.css = bgCSS({
w: b.geometry.w,
h: 1,
});
timeout(transition_duration / 2, () => {
b.css = bgCSS({
w: 1,
h: 1,
});
});
});
timeout(transition_duration, () => {
lock.unlock_and_destroy();
Gdk.Display.get_default()?.sync();
App.quit();
});
};
const Clock = () => {
const time = Variable<string>('').poll(1000, () => {
return (new Date().toLocaleString([], {
hour: 'numeric',
minute: 'numeric',
hour12: true,
}) ?? '')
.replace('a.m.', 'AM')
.replace('p.m.', 'PM');
});
return (
<label
className="lock-clock"
label={bind(time)}
/>
);
};
const PasswordPrompt = (monitor: Gdk.Monitor, visible: boolean) => {
const rev = new BlurredBox({ css: bgCSS() });
idle(() => {
rev.geometry = {
w: monitor.geometry.width,
h: monitor.geometry.height,
};
rev.css = bgCSS({
w: rev.geometry.w,
h: 1,
});
timeout(transition_duration / 2, () => {
rev.css = bgCSS({
w: rev.geometry.w,
h: rev.geometry.h,
});
});
});
blurBGs.push(rev);
<window
name={`blur-bg-${monitor.get_model()}`}
namespace={`blur-bg-${monitor.get_model()}`}
gdkmonitor={monitor}
layer={Astal.Layer.OVERLAY}
anchor={
Astal.WindowAnchor.TOP |
Astal.WindowAnchor.LEFT |
Astal.WindowAnchor.RIGHT |
Astal.WindowAnchor.BOTTOM
}
margin={WINDOW_MARGINS}
exclusivity={Astal.Exclusivity.IGNORE}
>
<box
halign={Gtk.Align.CENTER}
valign={Gtk.Align.CENTER}
>
{rev}
</box>
</window>;
const label = <label label="Enter password:" /> as Widget.Label;
return new Gtk.Window({
child: visible ?
(
<box
vertical
halign={Gtk.Align.CENTER}
valign={Gtk.Align.CENTER}
spacing={16}
>
<Clock />
<Separator size={CLOCK_SPACING} vertical />
<box
halign={Gtk.Align.CENTER}
className="avatar"
/>
<box
className="entry-box"
vertical
>
{label}
<Separator size={ENTRY_SPACING} vertical />
<entry
halign={Gtk.Align.CENTER}
xalign={0.5}
visibility={false}
placeholder_text="password"
onRealize={(self) => self.grab_focus()}
onActivate={(self) => {
self.sensitive = false;
AstalAuth.Pam.authenticate(self.text ?? '', (_, task) => {
try {
AstalAuth.Pam.authenticate_finish(task);
unlock();
}
catch (e) {
self.text = '';
label.label = (e as Error).message;
self.sensitive = true;
}
});
}}
/>
</box>
</box>
) :
<box />,
});
};
const createWindow = (monitor: Gdk.Monitor) => {
const hyprDesc = get_hyprland_monitor_desc(monitor);
const entryVisible = Vars.mainMonitor === hyprDesc || Vars.dupeLockscreen;
const win = PasswordPrompt(monitor, entryVisible);
windows.set(monitor, win);
};
const lock_screen = () => {
const display = Gdk.Display.get_default();
for (let m = 0; m < (display?.get_n_monitors() ?? 0); m++) {
const monitor = display?.get_monitor(m);
if (monitor) {
createWindow(monitor);
}
}
display?.connect('monitor-added', (_, monitor) => {
createWindow(monitor);
});
lock.lock_lock();
windows.forEach((win, monitor) => {
lock.new_surface(win, monitor);
win.show();
});
};
const on_finished = () => {
lock.destroy();
Gdk.Display.get_default()?.sync();
App.quit();
};
lock.connect('finished', on_finished);
if (Vars.hasFprintd) {
globalThis.authFinger = () => AstalAuth.Pam.authenticate('', (_, task) => {
try {
AstalAuth.Pam.authenticate_finish(task);
unlock();
}
catch (e) {
console.error((e as Error).message);
}
});
globalThis.authFinger();
}
lock_screen();
};

View file

@ -0,0 +1,4 @@
.lock-clock {
font-size: 80pt;
font-family: 'Ubuntu Mono';
}