diff --git a/nixosModules/ags/v2/app.ts b/nixosModules/ags/v2/app.ts
index 4ec28033..f99ce9a8 100644
--- a/nixosModules/ags/v2/app.ts
+++ b/nixosModules/ags/v2/app.ts
@@ -5,7 +5,7 @@ import style from './style.scss';
import Bar from './widgets/bar/wim';
import BgFade from './widgets/bg-fade/main';
import Corners from './widgets/corners/main';
-import { NotifPopups } from './widgets/notifs/main';
+import { NotifPopups, NotifCenter } from './widgets/notifs/main';
import MonitorClicks from './services/monitor-clicks';
@@ -18,6 +18,7 @@ App.start({
BgFade();
Corners();
NotifPopups();
+ NotifCenter();
new MonitorClicks();
},
diff --git a/nixosModules/ags/v2/services/monitor-clicks.ts b/nixosModules/ags/v2/services/monitor-clicks.ts
index 3562ffda..de74876f 100644
--- a/nixosModules/ags/v2/services/monitor-clicks.ts
+++ b/nixosModules/ags/v2/services/monitor-clicks.ts
@@ -113,26 +113,27 @@ export default class MonitorClicks extends GObject.Object {
return;
}
- const layers = JSON.parse(await hyprMessage('j/layers')) as LayerResult;
- const pos = JSON.parse(await hyprMessage('j/cursorpos')) as CursorPos;
+ try {
+ const layers = JSON.parse(await hyprMessage('j/layers')) as LayerResult;
+ const pos = JSON.parse(await hyprMessage('j/cursorpos')) as CursorPos;
- Object.values(layers).forEach((key) => {
- const overlayLayer = key.levels['3'];
+ Object.values(layers).forEach((key) => {
+ const overlayLayer = key.levels['3'];
- if (overlayLayer) {
- const noCloseWidgetsNames = [
- 'bar-',
- 'osk',
- ];
+ if (overlayLayer) {
+ const noCloseWidgetsNames = [
+ 'bar-',
+ 'osk',
+ ];
- const getNoCloseWidgets = (names: string[]) => {
- const arr = [] as Layer[];
+ const getNoCloseWidgets = (names: string[]) => {
+ const arr = [] as Layer[];
- names.forEach((name) => {
- arr.push(
- overlayLayer.find(
- (n) => n.namespace.startsWith(name),
- ) ||
+ names.forEach((name) => {
+ arr.push(
+ overlayLayer.find(
+ (n) => n.namespace.startsWith(name),
+ ) ||
// Return an empty Layer if widget doesn't exist
{
address: '',
@@ -142,44 +143,48 @@ export default class MonitorClicks extends GObject.Object {
h: 0,
namespace: '',
},
- );
- });
+ );
+ });
- return arr;
- };
- const clickIsOnWidget = (w: Layer) => {
- return pos.x > w.x && pos.x < w.x + w.w &&
+ return arr;
+ };
+ const clickIsOnWidget = (w: Layer) => {
+ return pos.x > w.x && pos.x < w.x + w.w &&
pos.y > w.y && pos.y < w.y + w.h;
- };
+ };
- const noCloseWidgets = getNoCloseWidgets(noCloseWidgetsNames);
+ const noCloseWidgets = getNoCloseWidgets(noCloseWidgetsNames);
- const widgets = overlayLayer.filter((n) => {
- let window = null as null | PopupWindow;
+ const widgets = overlayLayer.filter((n) => {
+ let window = null as null | PopupWindow;
- if (App.get_windows().some((win) =>
- win.name === n.namespace)) {
- window = (App.get_window(n.namespace) as PopupWindow);
- }
+ if (App.get_windows().some((win) =>
+ win.name === n.namespace)) {
+ window = (App.get_window(n.namespace) as PopupWindow);
+ }
- return window &&
+ return window &&
window.close_on_unfocus &&
window.close_on_unfocus ===
clickStage;
- });
-
- if (noCloseWidgets.some(clickIsOnWidget)) {
- // Don't handle clicks when on certain widgets
- }
- else {
- widgets.forEach((w) => {
- if (!(pos.x > w.x && pos.x < w.x + w.w &&
- pos.y > w.y && pos.y < w.y + w.h)) {
- App.get_window(w.namespace)?.set_visible(false);
- }
});
+
+ if (noCloseWidgets.some(clickIsOnWidget)) {
+ // Don't handle clicks when on certain widgets
+ }
+ else {
+ widgets.forEach((w) => {
+ if (!(pos.x > w.x && pos.x < w.x + w.w &&
+ pos.y > w.y && pos.y < w.y + w.h)) {
+ App.get_window(w.namespace)?.set_visible(false);
+ }
+ });
+ }
}
- }
- });
+ });
+ }
+ catch (e) {
+ console.log(e);
+ }
}
}
diff --git a/nixosModules/ags/v2/widgets/bar/fullscreen.tsx b/nixosModules/ags/v2/widgets/bar/fullscreen.tsx
index e7f5396b..3b5f9cc1 100644
--- a/nixosModules/ags/v2/widgets/bar/fullscreen.tsx
+++ b/nixosModules/ags/v2/widgets/bar/fullscreen.tsx
@@ -20,33 +20,38 @@ Hyprland.connect('event', async() => {
m1.size === m2.size &&
Array.from(m1.keys()).every((key) => m1.get(key) === m2.get(key));
- const newMonitors = JSON.parse(await hyprMessage('j/monitors')) as AstalHyprland.Monitor[];
+ try {
+ const newMonitors = JSON.parse(await hyprMessage('j/monitors')) as AstalHyprland.Monitor[];
- const fs = FullscreenState.get();
- const fsClients = Hyprland.get_clients().filter((c) => {
- const mon = newMonitors.find((monitor) => monitor.id === c.get_monitor().id);
+ const fs = FullscreenState.get();
+ const fsClients = Hyprland.get_clients().filter((c) => {
+ const mon = newMonitors.find((monitor) => monitor.id === c.get_monitor()?.id);
- return c.fullscreenClient !== 0 &&
- c.workspace.id === mon?.activeWorkspace.id;
- });
-
- const monitors = fsClients.map((c) =>
- get_monitor_desc(c.monitor));
-
- const clientAddrs = new Map(fsClients.map((c) => [
- get_monitor_desc(c.monitor),
- c.address ?? '',
- ]));
-
- const hasChanged =
- !arrayEquals(monitors, fs.monitors) ||
- !mapEquals(clientAddrs, fs.clientAddrs);
-
- if (hasChanged) {
- FullscreenState.set({
- monitors,
- clientAddrs,
+ return c.fullscreenClient !== 0 &&
+ c.workspace.id === mon?.activeWorkspace.id;
});
+
+ const monitors = fsClients.map((c) =>
+ get_monitor_desc(c.monitor));
+
+ const clientAddrs = new Map(fsClients.map((c) => [
+ get_monitor_desc(c.monitor),
+ c.address ?? '',
+ ]));
+
+ const hasChanged =
+ !arrayEquals(monitors, fs.monitors) ||
+ !mapEquals(clientAddrs, fs.clientAddrs);
+
+ if (hasChanged) {
+ FullscreenState.set({
+ monitors,
+ clientAddrs,
+ });
+ }
+ }
+ catch (e) {
+ console.log(e);
}
});
diff --git a/nixosModules/ags/v2/widgets/bar/items/current-client.tsx b/nixosModules/ags/v2/widgets/bar/items/current-client.tsx
index 163ea6f6..6225546c 100644
--- a/nixosModules/ags/v2/widgets/bar/items/current-client.tsx
+++ b/nixosModules/ags/v2/widgets/bar/items/current-client.tsx
@@ -39,7 +39,12 @@ export default () => {
Hyprland.connect('notify::focused-client', () => updateVars());
Hyprland.connect('client-removed', () => updateVars());
Hyprland.connect('client-added', async() => {
- updateVars(Hyprland.get_client(JSON.parse(await hyprMessage('j/activewindow')).address));
+ try {
+ updateVars(Hyprland.get_client(JSON.parse(await hyprMessage('j/activewindow')).address));
+ }
+ catch (e) {
+ console.log(e);
+ }
});
return (
diff --git a/nixosModules/ags/v2/widgets/bar/items/notif-button.tsx b/nixosModules/ags/v2/widgets/bar/items/notif-button.tsx
new file mode 100644
index 00000000..09f97acc
--- /dev/null
+++ b/nixosModules/ags/v2/widgets/bar/items/notif-button.tsx
@@ -0,0 +1,59 @@
+import { bind } from 'astal';
+import { App } from 'astal/gtk3';
+
+import AstalNotifd from 'gi://AstalNotifd?version=0.1';
+const Notifications = AstalNotifd.get_default();
+
+import Separator from '../../misc/separator';
+
+const SPACING = 4;
+
+// Types
+import { PopupWindow } from '../../misc/popup-window';
+
+
+export default () => (
+
+);
diff --git a/nixosModules/ags/v2/widgets/bar/items/workspaces.tsx b/nixosModules/ags/v2/widgets/bar/items/workspaces.tsx
index 2c6d64ea..29151f3f 100644
--- a/nixosModules/ags/v2/widgets/bar/items/workspaces.tsx
+++ b/nixosModules/ags/v2/widgets/bar/items/workspaces.tsx
@@ -19,7 +19,7 @@ const Workspace = ({ id = 0 }) => (
tooltip_text={id.toString()}
onClickRelease={() => {
- hyprMessage(`dispatch workspace ${id}`);
+ hyprMessage(`dispatch workspace ${id}`).catch(console.log);
}}
>
(
+
+
+
+
diff --git a/nixosModules/ags/v2/widgets/misc/popup-window.tsx b/nixosModules/ags/v2/widgets/misc/popup-window.tsx
index 81d47069..fabd05fa 100644
--- a/nixosModules/ags/v2/widgets/misc/popup-window.tsx
+++ b/nixosModules/ags/v2/widgets/misc/popup-window.tsx
@@ -1,8 +1,8 @@
-import { App, Astal, Widget } from 'astal/gtk3';
+import { App, Astal, Gtk, Widget } from 'astal/gtk3';
import { register, property } from 'astal/gobject';
import { Binding, idle } from 'astal';
-import { hyprMessage } from '../../lib';
+import { get_hyprland_monitor, hyprMessage } from '../../lib';
/* Types */
type CloseType = 'none' | 'stay' | 'released' | 'clicked';
@@ -60,7 +60,7 @@ export class PopupWindow extends Widget.Window {
App.add_window(this);
const setTransition = (_: PopupWindow, t: HyprTransition | Binding) => {
- hyprMessage(`keyword layerrule animation ${t}, ${this.name}`);
+ hyprMessage(`keyword layerrule animation ${t}, ${this.name}`).catch(console.log);
};
this.connect('notify::transition', setTransition);
@@ -82,6 +82,34 @@ export class PopupWindow extends Widget.Window {
}
});
};
+
+ set_x_pos(
+ alloc: Gtk.Allocation,
+ side = 'right' as 'left' | 'right',
+ ) {
+ const monitor = this.gdkmonitor ??
+ this.get_display().get_monitor_at_point(alloc.x, alloc.y);
+
+ // @ts-expect-error this should exist
+ const transform = get_hyprland_monitor(monitor)?.transform;
+
+ let width: number;
+
+ if (transform && (transform === 1 || transform === 3)) {
+ width = monitor.get_geometry().height;
+ }
+ else {
+ width = monitor.get_geometry().width;
+ }
+
+ this.margin_right = side === 'right' ?
+ (width - alloc.x - alloc.width) :
+ this.margin_right;
+
+ this.margin_left = side === 'right' ?
+ this.margin_left :
+ (alloc.x - alloc.width);
+ }
}
export default (props: PopupWindowProps) => new PopupWindow(props);
diff --git a/nixosModules/ags/v2/widgets/notifs/gesture.tsx b/nixosModules/ags/v2/widgets/notifs/gesture.tsx
index 5f37dc79..d9b9faeb 100644
--- a/nixosModules/ags/v2/widgets/notifs/gesture.tsx
+++ b/nixosModules/ags/v2/widgets/notifs/gesture.tsx
@@ -63,41 +63,47 @@ export class NotifGestureWrapper extends Widget.EventBox {
public dragging: boolean;
private async get_hovered(): Promise {
- const layers = JSON.parse(await hyprMessage('j/layers')) as LayerResult;
- const cursorPos = JSON.parse(await hyprMessage('j/cursorpos')) as CursorPos;
+ try {
+ const layers = JSON.parse(await hyprMessage('j/layers')) as LayerResult;
+ const cursorPos = JSON.parse(await hyprMessage('j/cursorpos')) as CursorPos;
- const window = this.get_window();
+ const window = this.get_window();
- if (window) {
- const monitor = display?.get_monitor_at_window(window);
+ if (window) {
+ const monitor = display?.get_monitor_at_window(window);
- if (monitor) {
- const plugName = get_hyprland_monitor(monitor)?.name;
- const notifLayer = layers[plugName ?? '']?.levels['3']
- ?.find((n) => n.namespace === 'notifications');
+ if (monitor) {
+ const plugName = get_hyprland_monitor(monitor)?.name;
+ const notifLayer = layers[plugName ?? '']?.levels['3']
+ ?.find((n) => n.namespace === 'notifications');
- if (notifLayer) {
- const index = [...NotifGestureWrapper.popups.keys()]
- .sort((a, b) => b - a)
- .indexOf(this.id);
+ if (notifLayer) {
+ const index = [...NotifGestureWrapper.popups.keys()]
+ .sort((a, b) => b - a)
+ .indexOf(this.id);
- const popups = [...NotifGestureWrapper.popups.entries()]
- .sort((a, b) => b[0] - a[0])
- .map(([key, val]) => [key, val.get_allocated_height()]);
+ const popups = [...NotifGestureWrapper.popups.entries()]
+ .sort((a, b) => b[0] - a[0])
+ .map(([key, val]) => [key, val.get_allocated_height()]);
- const thisY = notifLayer.y + popups
- .map((v) => v[1])
- .slice(0, index)
- .reduce((prev, curr) => prev + curr, 0);
+ const thisY = notifLayer.y + popups
+ .map((v) => v[1])
+ .slice(0, index)
+ .reduce((prev, curr) => prev + curr, 0);
- if (cursorPos.y >= thisY && cursorPos.y <= thisY + (popups[index][1] ?? 0)) {
- if (cursorPos.x >= notifLayer.x && cursorPos.x <= notifLayer.x + notifLayer.w) {
- return true;
+ if (cursorPos.y >= thisY && cursorPos.y <= thisY + (popups[index][1] ?? 0)) {
+ if (cursorPos.x >= notifLayer.x &&
+ cursorPos.x <= notifLayer.x + notifLayer.w) {
+ return true;
+ }
}
}
}
}
}
+ catch (e) {
+ console.log(e);
+ }
return false;
}
diff --git a/nixosModules/ags/v2/widgets/notifs/main.tsx b/nixosModules/ags/v2/widgets/notifs/main.tsx
index b78f3945..21247b52 100644
--- a/nixosModules/ags/v2/widgets/notifs/main.tsx
+++ b/nixosModules/ags/v2/widgets/notifs/main.tsx
@@ -1,5 +1,7 @@
import { Astal } from 'astal/gtk3';
+import PopupWindow from '../misc/popup-window';
+
import Popups from './popups';
@@ -13,3 +15,12 @@ export const NotifPopups = () => (
);
+
+export const NotifCenter = () => (
+
+
+
+);