diff --git a/nixosModules/ags/config/app.ts b/nixosModules/ags/config/app.ts index ac690a4c..20af41a4 100644 --- a/nixosModules/ags/config/app.ts +++ b/nixosModules/ags/config/app.ts @@ -2,8 +2,23 @@ // TODO: quick-settings // TODO: music player stuff // TODO: on-screen-keyboard +// TODO: see if I can bundle each config separately with nix -import GLib from 'gi://GLib'; +import { programArgs } from 'system'; + +import binto from './configurations/binto'; +import wim from './configurations/wim'; + +import greeter from './configurations/greeter'; +import lock from './configurations/lock'; -(await import(`./configurations/${GLib.getenv('CONF')}.ts`)).default(); +switch (programArgs[0]) { + case 'binto': binto(); break; + + case 'wim': wim(); break; + + case 'greeter': greeter(); break; + + case 'lock': lock(); break; +} diff --git a/nixosModules/ags/config/configurations/binto.ts b/nixosModules/ags/config/configurations/binto.ts index db27ec3d..8bb571c7 100644 --- a/nixosModules/ags/config/configurations/binto.ts +++ b/nixosModules/ags/config/configurations/binto.ts @@ -1,25 +1,25 @@ -export default async() => { - const { execAsync } = await import('astal'); - const { App } = await import('astal/gtk3'); +import { execAsync } from 'astal'; +import { App } from 'astal/gtk3'; - const style = (await import('../style/main.scss')).default; +import style from '../style/main.scss'; - const AppLauncher = (await import('../widgets/applauncher/main')).default; - const Bar = (await import('../widgets/bar/binto')).default; - const BgLayer = (await import('../widgets/bg-layer/main')).default; - const Calendar = (await import('../widgets/date/binto')).default; - const Clipboard = (await import('../widgets/clipboard/main')).default; - const { NotifPopups, NotifCenter } = await import('../widgets/notifs/binto'); - const OSD = (await import('../widgets/osd/main')).default; - const PowerMenu = (await import('../widgets/powermenu/main')).default; - const Screenshot = (await import('../widgets/screenshot/main')).default; +import AppLauncher from '../widgets/applauncher/main'; +import Bar from '../widgets/bar/binto'; +import BgLayer from '../widgets/bg-layer/main'; +import Calendar from '../widgets/date/binto'; +import Clipboard from '../widgets/clipboard/main'; +import { NotifPopups, NotifCenter } from '../widgets/notifs/binto'; +import OSD from '../widgets/osd/main'; +import PowerMenu from '../widgets/powermenu/main'; +import Screenshot from '../widgets/screenshot/main'; - const { closeAll, perMonitor } = await import('../lib'); - const Brightness = (await import('../services/brightness')).default; - const GSR = (await import('../services/gpu-screen-recorder')).default; - const MonitorClicks = (await import('../services/monitor-clicks')).default; +import { closeAll, perMonitor } from '../lib'; +import Brightness from '../services/brightness'; +import GSR from '../services/gpu-screen-recorder'; +import MonitorClicks from '../services/monitor-clicks'; +export default () => { App.start({ css: style, @@ -61,9 +61,8 @@ export default async() => { PowerMenu(); Screenshot(); - Brightness.initService({ - caps: 'input2::capslock', - }); + Brightness.initService({ caps: 'input2::capslock' }); + GSR.initService(); new MonitorClicks(); }, }); diff --git a/nixosModules/ags/config/configurations/greeter.ts b/nixosModules/ags/config/configurations/greeter.ts index 3403d29b..ad2517eb 100644 --- a/nixosModules/ags/config/configurations/greeter.ts +++ b/nixosModules/ags/config/configurations/greeter.ts @@ -1,12 +1,12 @@ -export default async() => { - const { execAsync } = await import('astal'); - const { App } = await import('astal/gtk3'); +import { execAsync } from 'astal'; +import { App } from 'astal/gtk3'; - const Greeter = (await import('../widgets/greeter/main')).default; +import Greeter from '../widgets/greeter/main'; - const style = (await import('../style/greeter.scss')).default; +import style from '../style/greeter.scss'; +export default () => { App.start({ css: style, instanceName: 'greeter', diff --git a/nixosModules/ags/config/configurations/lock.ts b/nixosModules/ags/config/configurations/lock.ts index a551efb4..55d56145 100644 --- a/nixosModules/ags/config/configurations/lock.ts +++ b/nixosModules/ags/config/configurations/lock.ts @@ -1,11 +1,11 @@ -export default async() => { - const { App } = await import('astal/gtk3'); +import { App } from 'astal/gtk3'; - const Lockscreen = (await import('../widgets/lockscreen/main')).default; +import Lockscreen from '../widgets/lockscreen/main'; - const style = (await import('../style/lock.scss')).default; +import style from '../style/lock.scss'; +export default () => { App.start({ css: style, instanceName: 'lock', diff --git a/nixosModules/ags/config/configurations/wim.ts b/nixosModules/ags/config/configurations/wim.ts index 2f0aceb3..692f586b 100644 --- a/nixosModules/ags/config/configurations/wim.ts +++ b/nixosModules/ags/config/configurations/wim.ts @@ -1,26 +1,26 @@ -export default async() => { - const { execAsync } = await import('astal'); - const { App } = await import('astal/gtk3'); +import { execAsync } from 'astal'; +import { App } from 'astal/gtk3'; - const style = (await import('../style/main.scss')).default; +import style from '../style/main.scss'; - const AppLauncher = (await import('../widgets/applauncher/main')).default; - const Bar = (await import('../widgets/bar/wim')).default; - const BgLayer = (await import('../widgets/bg-layer/main')).default; - const Calendar = (await import('../widgets/date/wim')).default; - const Clipboard = (await import('../widgets/clipboard/main')).default; - const Corners = (await import('../widgets/corners/main')).default; - const IconBrowser = (await import('../widgets/icon-browser/main')).default; - const { NotifPopups, NotifCenter } = await import('../widgets/notifs/wim'); - const OSD = (await import('../widgets/osd/main')).default; - const PowerMenu = (await import('../widgets/powermenu/main')).default; - const Screenshot = (await import('../widgets/screenshot/main')).default; +import AppLauncher from '../widgets/applauncher/main'; +import Bar from '../widgets/bar/wim'; +import BgLayer from '../widgets/bg-layer/main'; +import Calendar from '../widgets/date/wim'; +import Clipboard from '../widgets/clipboard/main'; +import Corners from '../widgets/corners/main'; +import IconBrowser from '../widgets/icon-browser/main'; +import { NotifPopups, NotifCenter } from '../widgets/notifs/wim'; +import OSD from '../widgets/osd/main'; +import PowerMenu from '../widgets/powermenu/main'; +import Screenshot from '../widgets/screenshot/main'; - const { closeAll, perMonitor } = await import('../lib'); - const Brightness = (await import('../services/brightness')).default; - const MonitorClicks = (await import('../services/monitor-clicks')).default; +import { closeAll, perMonitor } from '../lib'; +import Brightness from '../services/brightness'; +import MonitorClicks from '../services/monitor-clicks'; +export default () => { App.start({ css: style, diff --git a/nixosModules/ags/config/services/gpu-screen-recorder.ts b/nixosModules/ags/config/services/gpu-screen-recorder.ts index 8509b07a..5e01ab1c 100644 --- a/nixosModules/ags/config/services/gpu-screen-recorder.ts +++ b/nixosModules/ags/config/services/gpu-screen-recorder.ts @@ -75,25 +75,28 @@ const notifySend = ({ class GSR extends GObject.Object { private _lastNotifID: number | undefined; - constructor() { - super(); + public initService() { + try { + subprocess( + ['gsr-start'], + (path) => { + if (!this._lastNotifID) { + console.error('[GSR] ID of warning notif not found'); - subprocess( - ['gsr-start'], - (path) => { - if (!this._lastNotifID) { - console.error('[GSR] ID of warning notif not found'); - - setTimeout(() => { + setTimeout(() => { + this._onSaved(path); + }, 1000); + } + else { this._onSaved(path); - }, 1000); - } - else { - this._onSaved(path); - } - }, - () => { /**/ }, - ); + } + }, + () => { /**/ }, + ); + } + catch (_e) { + console.error('Missing dependency for gpu-screen-recorder'); + } } public saveReplay() { diff --git a/nixosModules/ags/config/widgets/greeter/main.tsx b/nixosModules/ags/config/widgets/greeter/main.tsx index fbb5af64..668cd050 100644 --- a/nixosModules/ags/config/widgets/greeter/main.tsx +++ b/nixosModules/ags/config/widgets/greeter/main.tsx @@ -4,92 +4,84 @@ import { App, Astal, Gtk, Widget } from 'astal/gtk3'; import AstalGreet from 'gi://AstalGreet'; -const DEFAULT_NAME = 'matt'; -const PARSED_INDEX = { - name: 0, - uid: 2, - gid: 3, - desc: 4, - home: 5, - shell: 6, -}; +export default () => { + const DEFAULT_NAME = 'matt'; + const PARSED_INDEX = { + name: 0, + uid: 2, + gid: 3, + desc: 4, + home: 5, + shell: 6, + }; -const parsePasswd = (fileContent: string) => { - const splitUsers = fileContent.split('\n'); - const parsedUsers = splitUsers.map((u) => { - const user = u.split(':'); + const parsePasswd = (fileContent: string) => { + const splitUsers = fileContent.split('\n'); + const parsedUsers = splitUsers.map((u) => { + const user = u.split(':'); - return { - name: user[PARSED_INDEX.name], - uid: Number(user[PARSED_INDEX.uid]), - gid: Number(user[PARSED_INDEX.gid]), - desc: user[PARSED_INDEX.desc], - home: user[PARSED_INDEX.home], - shell: user[PARSED_INDEX.shell], - }; + return { + name: user[PARSED_INDEX.name], + uid: Number(user[PARSED_INDEX.uid]), + gid: Number(user[PARSED_INDEX.gid]), + desc: user[PARSED_INDEX.desc], + home: user[PARSED_INDEX.home], + shell: user[PARSED_INDEX.shell], + }; + }); + + // 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(readFile('/etc/passwd')); + + const dropdown = new Gtk.ComboBoxText(); + + dropdown.show_all(); + + users.forEach((u) => { + dropdown.append(null, u.name); }); - // Filter out system users, nixbld users and nobody - return parsedUsers.filter((u) => { - return u.uid >= 1000 && - !u.name.includes('nixbld') && - u.name !== 'nobody'; - }); -}; + const response = <label /> as Widget.Label; -const users = parsePasswd(readFile('/etc/passwd')); + const password = ( + <entry + placeholderText="Password" + visibility={false} -const dropdown = new Gtk.ComboBoxText(); + setup={(self) => idle(() => { + self.grab_focus(); + })} -dropdown.show_all(); + onActivate={(self) => { + AstalGreet.login( + dropdown.get_active_text() ?? '', + self.text || '', + 'Hyprland', + (_, res) => { + try { + AstalGreet.login_finish(res); + App.quit(); + } + catch (error) { + response.label = JSON.stringify(error); + } + }, + ); + }} + /> + ); -users.forEach((u) => { - dropdown.append(null, u.name); -}); - -const response = <label /> as Widget.Label; - -const password = ( - <entry - placeholderText="Password" - visibility={false} - - setup={(self) => idle(() => { - self.grab_focus(); - })} - - onActivate={(self) => { - AstalGreet.login( - dropdown.get_active_text() ?? '', - self.text || '', - 'Hyprland', - (_, res) => { - try { - AstalGreet.login_finish(res); - App.quit(); - } - catch (error) { - response.label = JSON.stringify(error); - } - }, - ); - }} - /> -); - - -export default () => ( - <window - name="greeter" - keymode={Astal.Keymode.ON_DEMAND} - > - <box - vertical - halign={Gtk.Align.CENTER} - valign={Gtk.Align.CENTER} - hexpand - vexpand - className="base" + return ( + <window + name="greeter" + keymode={Astal.Keymode.ON_DEMAND} > <box vertical @@ -97,23 +89,32 @@ export default () => ( valign={Gtk.Align.CENTER} hexpand vexpand - className="linked" - - setup={() => { - idle(() => { - const usernames = users.map((u) => u.name); - - if (usernames.includes(DEFAULT_NAME)) { - dropdown.set_active(usernames.indexOf(DEFAULT_NAME)); - } - }); - }} + className="base" > - {dropdown} - {password} - </box> + <box + vertical + halign={Gtk.Align.CENTER} + valign={Gtk.Align.CENTER} + hexpand + vexpand + className="linked" - {response} - </box> - </window> -); + setup={() => { + idle(() => { + const usernames = users.map((u) => u.name); + + if (usernames.includes(DEFAULT_NAME)) { + dropdown.set_active(usernames.indexOf(DEFAULT_NAME)); + } + }); + }} + > + {dropdown} + {password} + </box> + + {response} + </box> + </window> + ); +}; diff --git a/nixosModules/ags/config/widgets/lockscreen/main.tsx b/nixosModules/ags/config/widgets/lockscreen/main.tsx index 925cd1d2..995c2eeb 100644 --- a/nixosModules/ags/config/widgets/lockscreen/main.tsx +++ b/nixosModules/ags/config/widgets/lockscreen/main.tsx @@ -21,222 +21,221 @@ class BlurredBox extends Widget.Box { } -const windows = new Map<Gdk.Monitor, Gtk.Window>(); -const blurBGs: BlurredBox[] = []; +export default () => { + const windows = new Map<Gdk.Monitor, Gtk.Window>(); + const blurBGs: BlurredBox[] = []; -const transition_duration = 1000; -const WINDOW_MARGINS = -2; -const ENTRY_SPACING = 20; -const CLOCK_SPACING = 60; + 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 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 lock = Lock.prepare_lock(); + const lock = Lock.prepare_lock(); -const unlock = () => { - blurBGs.forEach((b) => { - b.css = bgCSS({ - w: b.geometry.w, - h: 1, - }); - - timeout(transition_duration / 2, () => { + const unlock = () => { + blurBGs.forEach((b) => { b.css = bgCSS({ - w: 1, + w: b.geometry.w, 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, + 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(); + }); + }; - blurBGs.push(rev); + 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'); + }); - <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} + 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} > - {rev} - </box> - </window>; + <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 /> + const label = <label label="Enter password:" /> as Widget.Label; + return new Gtk.Window({ + child: visible ? + ( <box - halign={Gtk.Align.CENTER} - className="avatar" - /> - - <box - className="entry-box" vertical + halign={Gtk.Align.CENTER} + valign={Gtk.Align.CENTER} + spacing={16} > - {label} + <Clock /> - <Separator size={ENTRY_SPACING} vertical /> + <Separator size={CLOCK_SPACING} vertical /> - <entry + <box 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; - } - }); - }} + 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> - ) : - <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); + 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); -}; + windows.set(monitor, win); + }; -const lock_screen = () => { - const display = Gdk.Display.get_default(); + 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); + for (let m = 0; m < (display?.get_n_monitors() ?? 0); m++) { + const monitor = display?.get_monitor(m); - if (monitor) { + 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(); } - - 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(); -} - -export default () => { lock_screen(); }; diff --git a/nixosModules/ags/packages.nix b/nixosModules/ags/packages.nix index 6ee938ae..ed872ee7 100644 --- a/nixosModules/ags/packages.nix +++ b/nixosModules/ags/packages.nix @@ -26,8 +26,10 @@ in { "cava" "powerprofiles" "river" - "docs" # not a lib - "gjs" # not a lib + + # Not libraries + "docs" + "gjs" ] ) ++ [gtk-session-lock.packages.${pkgs.system}.default]; @@ -36,10 +38,8 @@ in { name = "lock"; runtimeInputs = [cfg.package]; text = '' - export CONF="lock" - if [ "$#" == 0 ]; then - exec ags run ~/${cfg.configDir} + exec ags run ~/${cfg.configDir} -a lock else exec ags "$@" -i lock fi @@ -54,10 +54,8 @@ in { name = "ags"; runtimeInputs = [cfg.package]; text = '' - export CONF="${hostName}" - if [ "$#" == 0 ]; then - exec ags run ~/${cfg.configDir} + exec ags run ~/${cfg.configDir} -a ${hostName} else exec ags "$@" fi @@ -67,8 +65,7 @@ in { name = "agsConf"; runtimeInputs = [cfg.package]; text = '' - export CONF="$1" - exec ${cfg.package}/bin/ags run ~/${cfg.configDir} + exec ags run ~/${cfg.configDir} -a "$1" ''; }) ] diff --git a/nixosModules/desktop/manager/ags.nix b/nixosModules/desktop/manager/ags.nix index 482d3c5e..1ed498be 100644 --- a/nixosModules/desktop/manager/ags.nix +++ b/nixosModules/desktop/manager/ags.nix @@ -54,8 +54,7 @@ self: { ]; text = '' - export CONF="greeter" - exec ags run ${agsConfig} + exec ags run ${agsConfig} -a greeter ''; }) ];