feat(agsV2): get notif cursors right
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-15 23:56:11 -04:00
parent 531ec67e0e
commit 2ee60de237
4 changed files with 123 additions and 53 deletions

View file

@ -5,7 +5,35 @@ import { idle } from 'astal';
import AstalNotifd from 'gi://AstalNotifd?version=0.1';
const Notifications = AstalNotifd.get_default();
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
const Hyprland = AstalHyprland.get_default();
import { HasNotifs } from './notification';
import { get_hyprland_monitor } from '../../lib';
/* Types */
interface Layer {
address: string
x: number
y: number
w: number
h: number
namespace: string
}
interface Levels {
0?: Layer[] | null
1?: Layer[] | null
2?: Layer[] | null
3?: Layer[] | null
}
interface Layers {
levels: Levels
}
type LayerResult = Record<string, Layers>;
interface CursorPos {
x: number
y: number
}
const display = Gdk.Display.get_default();
@ -36,19 +64,77 @@ type NotifGestureWrapperProps = Widget.BoxProps & {
};
@register()
class NotifGestureWrapper extends Widget.EventBox {
export class NotifGestureWrapper extends Widget.EventBox {
static popups = new Map<number, NotifGestureWrapper>();
readonly id: number;
readonly slide_in_from: 'Left' | 'Right';
readonly slideAway: (side: 'Left' | 'Right') => void;
@property(Boolean)
declare hovered: boolean;
@property(Boolean)
declare dragging: boolean;
get hovered(): boolean {
const layers = JSON.parse(Hyprland.message('j/layers')) as LayerResult;
const cursorPos = JSON.parse(Hyprland.message('j/cursorpos')) as CursorPos;
const window = this.get_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 (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 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;
}
}
}
}
}
return false;
}
public slideAway(side: 'Left' | 'Right', force = false) {
((this.get_child() as Widget.Revealer).get_child() as Widget.Box)
.css = side === 'Left' ? slideLeft : slideRight;
// Make it uninteractable
this.sensitive = false;
setTimeout(() => {
(this.get_child() as Widget.Revealer).revealChild = false;
setTimeout(() => {
// Kill notif and update HasNotifs after anim is done
if (force) {
Notifications.get_notification(this.id)?.dismiss();
}
HasNotifs.set(Notifications.get_notifications().length > 0);
this.destroy();
}, ANIM_DURATION);
}, ANIM_DURATION - 100);
}
constructor({
id,
slide_in_from = 'Left',
@ -57,36 +143,8 @@ class NotifGestureWrapper extends Widget.EventBox {
super();
this.id = id;
this.dragging = false;
this.hovered = false;
this.slide_in_from = slide_in_from;
this.slideAway = (side: 'Left' | 'Right', force = false) => {
((this.get_child() as Widget.Revealer).get_child() as Widget.Box)
.css = side === 'Left' ? slideLeft : slideRight;
// Make it uninteractable
this.sensitive = false;
setTimeout(() => {
(this.get_child() as Widget.Revealer).revealChild = false;
setTimeout(() => {
// Kill notif and update HasNotifs after anim is done
if (force) {
Notifications.get_notification(this.id)?.dismiss();
}
HasNotifs.set(Notifications.get_notifications().length > 0);
this.destroy();
}, ANIM_DURATION);
}, ANIM_DURATION - 100);
};
this.connect('notify::dragging', () => {
if (!this.hovered && this.dragging) {
this.hovered = true;
}
});
// OnClick
this.connect('button-press-event', () => {
if (!display) {
@ -96,9 +154,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display,
'grabbing',
));
if (!this.hovered) {
this.hovered = true;
}
});
// OnRelease
@ -110,9 +165,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display,
'grab',
));
if (!this.hovered) {
this.hovered = true;
}
});
// OnHover
@ -124,9 +176,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display,
'grab',
));
if (!this.hovered) {
this.hovered = true;
}
});
// OnHoverLost
@ -138,10 +187,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display,
'grab',
));
if (this.hovered) {
this.hovered = false;
}
});
const gesture = Gtk.GestureDrag.new(this);

View file

@ -6,6 +6,7 @@ import Popups from './popups';
export const NotifPopups = () => (
<window
name="notifications"
namespace="notifications"
layer={Astal.Layer.OVERLAY}
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT}
>

View file

@ -1,4 +1,4 @@
import { App, Gtk } from 'astal/gtk3';
import { App, Gtk, Gdk } from 'astal/gtk3';
import { Variable } from 'astal';
import GLib from 'gi://GLib?version=2.0';
@ -60,6 +60,29 @@ const NotifIcon = ({ notifObj }: { notifObj: AstalNotifd.Notification }) => {
);
};
const setupButton = (self: Gtk.Widget) => {
const display = Gdk.Display.get_default();
// OnHover
self.connect('enter-notify-event', () => {
if (!display) {
return;
}
self.window.set_cursor(Gdk.Cursor.new_from_name(
display,
'pointer',
));
});
// OnHoverLost
self.connect('leave-notify-event', () => {
if (!display) {
return;
}
self.window.set_cursor(null);
});
};
const BlockedApps = [
'Spotify',
];
@ -119,6 +142,7 @@ export const Notification = ({
className="close-button"
valign={Gtk.Align.START}
halign={Gtk.Align.END}
setup={setupButton}
onButtonReleaseEvent={() => {
notifObj.dismiss();
@ -147,6 +171,7 @@ export const Notification = ({
<button
className="action-button"
hexpand
setup={setupButton}
onButtonReleaseEvent={() => notifObj.invoke(action.id)}
>

View file

@ -1,6 +1,7 @@
import AstalNotifd from 'gi://AstalNotifd?version=0.1';
const Notifications = AstalNotifd.get_default();
import { NotifGestureWrapper } from './gesture';
import { Notification } from './notification';
@ -11,8 +12,6 @@ export default () => (
vertical
setup={(self) => {
const NotifsMap = new Map<number, ReturnType<typeof Notification>>();
const addPopup = (id: number) => {
if (!id) {
return;
@ -25,19 +24,19 @@ export default () => (
self.pack_end(NewNotif, false, false, 0);
self.show_all();
NotifsMap.set(id, NewNotif);
NotifGestureWrapper.popups.set(id, NewNotif);
}
};
const handleResolved = (id: number) => {
const notif = NotifsMap.get(id);
const notif = NotifGestureWrapper.popups.get(id);
if (!notif) {
return;
}
notif.slideAway('Left');
NotifsMap.delete(id);
NotifGestureWrapper.popups.delete(id);
};
self