feat(agsV2): add lockscreen
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
9f764bf21b
commit
e03d34d75b
7 changed files with 316 additions and 20 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -13,7 +13,7 @@ result*
|
||||||
.nixd.json
|
.nixd.json
|
||||||
|
|
||||||
## AGS
|
## AGS
|
||||||
nixosModules/ags/config/ts/lockscreen/vars.ts
|
**/vars.ts
|
||||||
**/config.js
|
**/config.js
|
||||||
*icons
|
*icons
|
||||||
**/types
|
**/types
|
||||||
|
|
|
@ -21,6 +21,7 @@ in {
|
||||||
mkIf cfgDesktop.ags.enable {
|
mkIf cfgDesktop.ags.enable {
|
||||||
# Enable pam for ags
|
# Enable pam for ags
|
||||||
security.pam.services.ags = {};
|
security.pam.services.ags = {};
|
||||||
|
security.pam.services.astal-auth = {};
|
||||||
|
|
||||||
services.upower.enable = true;
|
services.upower.enable = true;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import { App } from 'astal/gtk3';
|
import { App } from 'astal/gtk3';
|
||||||
|
|
||||||
|
import GLib from 'gi://GLib?version=2.0';
|
||||||
|
|
||||||
import style from './style.scss';
|
import style from './style.scss';
|
||||||
|
|
||||||
import AppLauncher from './widgets/applauncher/main';
|
import AppLauncher from './widgets/applauncher/main';
|
||||||
|
@ -13,8 +15,27 @@ import PowerMenu from './widgets/powermenu/main';
|
||||||
|
|
||||||
import MonitorClicks from './services/monitor-clicks';
|
import MonitorClicks from './services/monitor-clicks';
|
||||||
|
|
||||||
|
import Lockscreen from './widgets/lockscreen/main';
|
||||||
|
|
||||||
App.start({
|
|
||||||
|
const CONF = GLib.getenv('CONF');
|
||||||
|
|
||||||
|
switch (CONF) {
|
||||||
|
case 'lock': {
|
||||||
|
App.start({
|
||||||
|
css: style,
|
||||||
|
instanceName: CONF,
|
||||||
|
|
||||||
|
main: () => {
|
||||||
|
Lockscreen();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'wim': {
|
||||||
|
App.start({
|
||||||
css: style,
|
css: style,
|
||||||
|
|
||||||
main: () => {
|
main: () => {
|
||||||
|
@ -30,4 +51,8 @@ App.start({
|
||||||
|
|
||||||
new MonitorClicks();
|
new MonitorClicks();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,15 +1,22 @@
|
||||||
self: {
|
self: {
|
||||||
lib,
|
lib,
|
||||||
|
osConfig,
|
||||||
pkgs,
|
pkgs,
|
||||||
...
|
...
|
||||||
}: {
|
}: {
|
||||||
config = let
|
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};
|
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";
|
configDir = "/home/matt/.nix/nixosModules/ags/v2";
|
||||||
in {
|
in {
|
||||||
home = {
|
home = {
|
||||||
|
@ -17,7 +24,15 @@ self: {
|
||||||
(pkgs.writeShellApplication {
|
(pkgs.writeShellApplication {
|
||||||
name = "agsV2";
|
name = "agsV2";
|
||||||
text = ''
|
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"];
|
"lib" = ["ES2023"];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
"${configDir}/widgets/lockscreen/vars.ts".text =
|
||||||
|
# javascript
|
||||||
|
''
|
||||||
|
export default {
|
||||||
|
mainMonitor: '${cfgDesktop.mainMonitor}',
|
||||||
|
dupeLockscreen: ${boolToString cfgDesktop.displayManager.duplicateScreen},
|
||||||
|
hasFprintd: ${boolToString (hostName == "wim")},
|
||||||
|
};
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,5 +16,6 @@ window, viewport {
|
||||||
@import 'widgets/bar/style.scss';
|
@import 'widgets/bar/style.scss';
|
||||||
@import 'widgets/date/style.scss';
|
@import 'widgets/date/style.scss';
|
||||||
@import 'widgets/icon-browser/style.scss';
|
@import 'widgets/icon-browser/style.scss';
|
||||||
|
@import 'widgets/lockscreen/style.scss';
|
||||||
@import 'widgets/notifs/style.scss';
|
@import 'widgets/notifs/style.scss';
|
||||||
@import 'widgets/powermenu/style.scss';
|
@import 'widgets/powermenu/style.scss';
|
||||||
|
|
240
nixosModules/ags/v2/widgets/lockscreen/main.tsx
Normal file
240
nixosModules/ags/v2/widgets/lockscreen/main.tsx
Normal 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();
|
||||||
|
};
|
4
nixosModules/ags/v2/widgets/lockscreen/style.scss
Normal file
4
nixosModules/ags/v2/widgets/lockscreen/style.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.lock-clock {
|
||||||
|
font-size: 80pt;
|
||||||
|
font-family: 'Ubuntu Mono';
|
||||||
|
}
|
Loading…
Reference in a new issue