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'; import AstalNotifd from 'gi://AstalNotifd?version=0.1';
const Notifications = AstalNotifd.get_default(); const Notifications = AstalNotifd.get_default();
import AstalHyprland from 'gi://AstalHyprland?version=0.1';
const Hyprland = AstalHyprland.get_default();
import { HasNotifs } from './notification'; 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(); const display = Gdk.Display.get_default();
@ -36,19 +64,77 @@ type NotifGestureWrapperProps = Widget.BoxProps & {
}; };
@register() @register()
class NotifGestureWrapper extends Widget.EventBox { export class NotifGestureWrapper extends Widget.EventBox {
static popups = new Map<number, NotifGestureWrapper>();
readonly id: number; readonly id: number;
readonly slide_in_from: 'Left' | 'Right'; readonly slide_in_from: 'Left' | 'Right';
readonly slideAway: (side: 'Left' | 'Right') => void;
@property(Boolean)
declare hovered: boolean;
@property(Boolean) @property(Boolean)
declare dragging: 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({ constructor({
id, id,
slide_in_from = 'Left', slide_in_from = 'Left',
@ -57,36 +143,8 @@ class NotifGestureWrapper extends Widget.EventBox {
super(); super();
this.id = id; this.id = id;
this.dragging = false; this.dragging = false;
this.hovered = false;
this.slide_in_from = slide_in_from; 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 // OnClick
this.connect('button-press-event', () => { this.connect('button-press-event', () => {
if (!display) { if (!display) {
@ -96,9 +154,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display, display,
'grabbing', 'grabbing',
)); ));
if (!this.hovered) {
this.hovered = true;
}
}); });
// OnRelease // OnRelease
@ -110,9 +165,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display, display,
'grab', 'grab',
)); ));
if (!this.hovered) {
this.hovered = true;
}
}); });
// OnHover // OnHover
@ -124,9 +176,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display, display,
'grab', 'grab',
)); ));
if (!this.hovered) {
this.hovered = true;
}
}); });
// OnHoverLost // OnHoverLost
@ -138,10 +187,6 @@ class NotifGestureWrapper extends Widget.EventBox {
display, display,
'grab', 'grab',
)); ));
if (this.hovered) {
this.hovered = false;
}
}); });
const gesture = Gtk.GestureDrag.new(this); const gesture = Gtk.GestureDrag.new(this);

View file

@ -6,6 +6,7 @@ import Popups from './popups';
export const NotifPopups = () => ( export const NotifPopups = () => (
<window <window
name="notifications" name="notifications"
namespace="notifications"
layer={Astal.Layer.OVERLAY} layer={Astal.Layer.OVERLAY}
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.LEFT} 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 { Variable } from 'astal';
import GLib from 'gi://GLib?version=2.0'; 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 = [ const BlockedApps = [
'Spotify', 'Spotify',
]; ];
@ -119,6 +142,7 @@ export const Notification = ({
className="close-button" className="close-button"
valign={Gtk.Align.START} valign={Gtk.Align.START}
halign={Gtk.Align.END} halign={Gtk.Align.END}
setup={setupButton}
onButtonReleaseEvent={() => { onButtonReleaseEvent={() => {
notifObj.dismiss(); notifObj.dismiss();
@ -147,6 +171,7 @@ export const Notification = ({
<button <button
className="action-button" className="action-button"
hexpand hexpand
setup={setupButton}
onButtonReleaseEvent={() => notifObj.invoke(action.id)} onButtonReleaseEvent={() => notifObj.invoke(action.id)}
> >

View file

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