From 50fc642f0337a8cf0476d4f241dab1a6b490bf04 Mon Sep 17 00:00:00 2001 From: matt1432 Date: Wed, 16 Oct 2024 22:33:15 -0400 Subject: [PATCH] feat(agsV2): add notif-button in bar --- nixosModules/ags/v2/app.ts | 3 +- .../ags/v2/services/monitor-clicks.ts | 93 ++++++++++--------- .../ags/v2/widgets/bar/fullscreen.tsx | 53 ++++++----- .../v2/widgets/bar/items/current-client.tsx | 7 +- .../ags/v2/widgets/bar/items/notif-button.tsx | 59 ++++++++++++ .../ags/v2/widgets/bar/items/workspaces.tsx | 2 +- nixosModules/ags/v2/widgets/bar/style.scss | 6 ++ nixosModules/ags/v2/widgets/bar/wim.tsx | 5 + .../ags/v2/widgets/misc/popup-window.tsx | 34 ++++++- .../ags/v2/widgets/notifs/gesture.tsx | 52 ++++++----- nixosModules/ags/v2/widgets/notifs/main.tsx | 11 +++ 11 files changed, 228 insertions(+), 97 deletions(-) create mode 100644 nixosModules/ags/v2/widgets/bar/items/notif-button.tsx 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 = () => ( + + + +);