notifpopups: fix clicking opening sidebar

This commit is contained in:
2 * r + 2 * t 2025-04-02 19:48:18 +11:00
parent c131a0425e
commit 473e5a6b8a
4 changed files with 59 additions and 44 deletions

View file

@ -15,6 +15,7 @@ import { execAsync, idle, timeout, writeFileAsync } from "astal";
import { App } from "astal/gtk3";
import { style } from "config";
import { initConfig, updateConfig } from "config/funcs";
import AstalHyprland from "gi://AstalHyprland?version=0.1";
const isLayer = (name: string) =>
["base", "mantle", "crust"].includes(name) || name.startsWith("surface") || name.startsWith("overlay");
@ -75,9 +76,9 @@ App.start({
Palette.get_default().connect("notify::mode", () => loadStyleAsync().catch(console.error));
<Launcher />;
<NotifPopups />;
<Osds />;
<Session />;
Monitors.get_default().forEach(m => <NotifPopups monitor={m} />);
Monitors.get_default().forEach(m => <SideBar monitor={m} />);
Monitors.get_default().forEach(m => <Bar monitor={m} />);
Monitors.get_default().forEach(m => <ScreenCorners monitor={m} />);
@ -99,6 +100,8 @@ App.start({
if (request === "reload-css") loadStyleAsync().catch(console.error);
else if (request === "reload-config") updateConfig();
else if (request.startsWith("show")) App.get_window(request.split(" ")[1])?.show();
else if (request.startsWith("toggle"))
App.toggle_window(request.split(" ")[1] + AstalHyprland.get_default().focusedMonitor.id);
else if (request === "media play-pause") Players.get_default().lastPlayer?.play_pause();
else if (request === "media next") Players.get_default().lastPlayer?.next();
else if (request === "media previous") Players.get_default().lastPlayer?.previous();

View file

@ -25,6 +25,10 @@ interface SpacerClassNameProps {
afterSpacer?: boolean;
}
interface ModuleProps extends SpacerClassNameProps {
monitor: Monitor;
}
const hyprland = AstalHyprland.get_default();
const getBatteryIcon = (perc: number) => {
@ -70,8 +74,8 @@ const hookFocusedClientProp = (
callback(lastClient);
};
const switchPane = (name: string) => {
const sidebar = App.get_window("sidebar") as SideBar | null;
const switchPane = (monitor: Monitor, name: string) => {
const sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
if (sidebar) {
if (sidebar.visible && sidebar.shown.get() === name) sidebar.hide();
else sidebar.show();
@ -82,17 +86,17 @@ const switchPane = (name: string) => {
const spacerClassName = ({ beforeSpacer, afterSpacer }: SpacerClassNameProps) =>
`${beforeSpacer ? "before-spacer" : ""} ${afterSpacer ? "after-spacer" : ""}`;
const OSIcon = (props: SpacerClassNameProps) => (
const OSIcon = ({ monitor, ...props }: ModuleProps) => (
<button
visible={bind(config.modules.osIcon.enabled)}
className={`module os-icon ${spacerClassName(props)}`}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("dashboard")}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "dashboard")}
>
{osIcon}
</button>
);
const ActiveWindow = (props: SpacerClassNameProps) => (
const ActiveWindow = ({ monitor, ...props }: ModuleProps) => (
<box
visible={bind(config.modules.activeWindow.enabled)}
vertical={bind(config.vertical)}
@ -134,7 +138,7 @@ const ActiveWindow = (props: SpacerClassNameProps) => (
</box>
);
const MediaPlaying = (props: SpacerClassNameProps) => {
const MediaPlaying = ({ monitor, ...props }: ModuleProps) => {
const players = Players.get_default();
const getLabel = (fallback = "") =>
players.lastPlayer ? `${players.lastPlayer.title} - ${players.lastPlayer.artist}` : fallback;
@ -142,7 +146,7 @@ const MediaPlaying = (props: SpacerClassNameProps) => {
<button
visible={bind(config.modules.mediaPlaying.enabled)}
onClick={(_, event) => {
if (event.button === Astal.MouseButton.PRIMARY) switchPane("audio");
if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "audio");
else if (event.button === Astal.MouseButton.SECONDARY) players.lastPlayer?.play_pause();
else if (event.button === Astal.MouseButton.MIDDLE) players.lastPlayer?.raise();
}}
@ -222,7 +226,7 @@ const Workspace = ({ idx }: { idx: number }) => {
);
};
const Workspaces = (props: SpacerClassNameProps) => (
const Workspaces = ({ monitor, ...props }: ModuleProps) => (
<eventbox
visible={bind(config.modules.workspaces.enabled)}
onScroll={(_, event) => {
@ -253,7 +257,7 @@ const TrayItem = (item: AstalTray.TrayItem) => (
</menubutton>
);
const Tray = (props: SpacerClassNameProps) => {
const Tray = ({ monitor, ...props }: ModuleProps) => {
const visible = Variable.derive(
[config.modules.tray.enabled, bind(AstalTray.get_default(), "items")],
(e, i) => e && i.length > 0
@ -275,7 +279,7 @@ const Network = () => (
<button
onClick={(_, event) => {
const network = AstalNetwork.get_default();
if (event.button === Astal.MouseButton.PRIMARY) switchPane("connectivity");
if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "connectivity");
else if (event.button === Astal.MouseButton.SECONDARY) network.wifi.enabled = !network.wifi.enabled;
else if (event.button === Astal.MouseButton.MIDDLE)
execAsync("uwsm app -- gnome-control-center wifi").catch(() => {
@ -378,7 +382,7 @@ const BluetoothDevice = (device: AstalBluetooth.Device) => (
<button
visible={bind(device, "connected")}
onClick={(_, event) => {
if (event.button === Astal.MouseButton.PRIMARY) switchPane("connectivity");
if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "connectivity");
else if (event.button === Astal.MouseButton.SECONDARY)
device.disconnect_device((_, res) => device.disconnect_device_finish(res));
else if (event.button === Astal.MouseButton.MIDDLE)
@ -398,7 +402,7 @@ const Bluetooth = () => (
<box vertical={bind(config.vertical)} className="bluetooth">
<button
onClick={(_, event) => {
if (event.button === Astal.MouseButton.PRIMARY) switchPane("connectivity");
if (event.button === Astal.MouseButton.PRIMARY) switchPane(monitor, "connectivity");
else if (event.button === Astal.MouseButton.SECONDARY) AstalBluetooth.get_default().toggle();
else if (event.button === Astal.MouseButton.MIDDLE)
execAsync("uwsm app -- blueman-manager").catch(console.error);
@ -440,7 +444,7 @@ const Bluetooth = () => (
</box>
);
const StatusIcons = (props: SpacerClassNameProps) => (
const StatusIcons = ({ monitor, ...props }: ModuleProps) => (
<box
visible={bind(config.modules.statusIcons.enabled)}
vertical={bind(config.vertical)}
@ -451,10 +455,10 @@ const StatusIcons = (props: SpacerClassNameProps) => (
</box>
);
const PkgUpdates = (props: SpacerClassNameProps) => (
const PkgUpdates = ({ monitor, ...props }: ModuleProps) => (
<button
visible={bind(config.modules.pkgUpdates.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("packages")}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "packages")}
setup={self =>
setupCustomTooltip(
self,
@ -469,10 +473,10 @@ const PkgUpdates = (props: SpacerClassNameProps) => (
</button>
);
const NotifCount = (props: SpacerClassNameProps) => (
const NotifCount = ({ monitor, ...props }: ModuleProps) => (
<button
visible={bind(config.modules.notifCount.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("notifpane")}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "notifpane")}
setup={self =>
setupCustomTooltip(
self,
@ -500,7 +504,7 @@ const NotifCount = (props: SpacerClassNameProps) => (
</button>
);
const Battery = (props: SpacerClassNameProps) => {
const Battery = ({ monitor, ...props }: ModuleProps) => {
const visible = Variable.derive(
[config.modules.battery.enabled, bind(AstalBattery.get_default(), "isBattery")],
(e, i) => e && i
@ -553,10 +557,10 @@ const DateTimeVertical = (props: SpacerClassNameProps) => (
</box>
);
const DateTime = (props: SpacerClassNameProps) => (
const DateTime = ({ monitor, ...props }: ModuleProps) => (
<button
visible={bind(config.modules.dateTime.enabled)}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane("time")}
onClick={(_, event) => event.button === Astal.MouseButton.PRIMARY && switchPane(monitor, "time")}
setup={self =>
setupCustomTooltip(self, bindCurrentTime(bind(config.modules.dateTime.detailedFormat), undefined, self))
}
@ -565,7 +569,7 @@ const DateTime = (props: SpacerClassNameProps) => (
</button>
);
const Power = (props: SpacerClassNameProps) => (
const Power = ({ monitor, ...props }: ModuleProps) => (
<button
visible={bind(config.modules.power.enabled)}
className={`module power ${spacerClassName(props)}`}
@ -609,21 +613,21 @@ const Bar = ({ monitor }: { monitor: Monitor }) => {
return (
<centerbox vertical={bind(config.vertical)} className={bind(className)} onDestroy={() => className.drop()}>
<box vertical={bind(config.vertical)}>
<OSIcon />
<ActiveWindow />
<MediaPlaying beforeSpacer />
<OSIcon monitor={monitor} />
<ActiveWindow monitor={monitor} />
<MediaPlaying monitor={monitor} beforeSpacer />
<BrightnessSpacer monitor={monitor} />
</box>
<Workspaces beforeSpacer afterSpacer />
<Workspaces monitor={monitor} beforeSpacer afterSpacer />
<box vertical={bind(config.vertical)}>
<VolumeSpacer />
<Tray afterSpacer />
<StatusIcons />
<PkgUpdates />
<NotifCount />
<Battery />
<DateTime />
<Power />
<Tray monitor={monitor} afterSpacer />
<StatusIcons monitor={monitor} />
<PkgUpdates monitor={monitor} />
<NotifCount monitor={monitor} />
<Battery monitor={monitor} />
<DateTime monitor={monitor} />
<Power monitor={monitor} />
</box>
</centerbox>
);

View file

@ -1,11 +1,15 @@
import type { Monitor } from "@/services/monitors";
import { idle, timeout } from "astal";
import { App, Astal, Gtk } from "astal/gtk3";
import { notifpopups as config } from "config";
import AstalNotifd from "gi://AstalNotifd";
import { setupChildClickthrough } from "../utils/widgets";
import Notification from "../widgets/notification";
import type SideBar from "./sidebar";
export default () => (
export default ({ monitor }: { monitor: Monitor }) => (
<window
monitor={monitor.id}
namespace="caelestia-notifpopups"
anchor={Astal.WindowAnchor.TOP | Astal.WindowAnchor.RIGHT | Astal.WindowAnchor.BOTTOM}
>
@ -16,10 +20,9 @@ export default () => (
setup={self => {
const notifd = AstalNotifd.get_default();
const map = new Map<number, Notification>();
let notifsOpen = false;
self.hook(notifd, "notified", (self, id) => {
if (notifsOpen || notifd.dontDisturb) return;
if (notifd.dontDisturb) return;
const notification = notifd.get_notification(id);
@ -35,7 +38,11 @@ export default () => (
if (event.button === Astal.MouseButton.PRIMARY) {
if (notification.actions.length === 1)
notification.invoke(notification.actions[0].id);
else App.get_window("notifications")?.show();
else {
sidebar?.shown.set("notifpane");
sidebar?.show();
popup.destroyWithAnims();
}
}
// Dismiss on middle click
else if (event.button === Astal.MouseButton.MIDDLE) notification.dismiss();
@ -54,12 +61,13 @@ export default () => (
});
self.hook(notifd, "resolved", (_, id) => map.get(id)?.destroyWithAnims());
self.hook(App, "window-toggled", (_, window) => {
if (window.name === "notifications") {
notifsOpen = window.visible;
map.forEach(n => n.destroyWithAnims());
}
});
let sidebar: SideBar | null;
const awaitSidebar = () => {
sidebar = App.get_window(`sidebar${monitor.id}`) as SideBar | null;
if (!sidebar) timeout(100, awaitSidebar);
};
idle(awaitSidebar);
// Change input region to child region so can click through empty space
setupChildClickthrough(self);

View file

@ -16,7 +16,7 @@ export default class SideBar extends Widget.Window {
constructor({ monitor }: { monitor: Monitor }) {
super({
application: App,
name: "sidebar",
name: `sidebar${monitor.id}`,
namespace: "caelestia-sidebar",
monitor: monitor.id,
anchor: Astal.WindowAnchor.LEFT | Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM,