feat(agsV2): get notif cursors right
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
531ec67e0e
commit
2ee60de237
4 changed files with 123 additions and 53 deletions
|
@ -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);
|
||||
|
|
|
@ -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}
|
||||
>
|
||||
|
|
|
@ -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)}
|
||||
>
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue