💥 fix: can't convert non-null pointer to js value
Thanks aylur!!
This commit is contained in:
+17
-9
@@ -1,6 +1,8 @@
|
||||
// fix ags needing --gtk 4
|
||||
// import app from "ags/gtk4/app";
|
||||
|
||||
// fix can't convert non-null pointer to JS value (thanks Aylur!)
|
||||
import "/usr/share/ags/js/src/overrides";
|
||||
import {
|
||||
PluginApps,
|
||||
PluginClipboard,
|
||||
@@ -9,7 +11,6 @@ import {
|
||||
PluginWallpapers,
|
||||
PluginWebSearch
|
||||
} from "./runner/plugins";
|
||||
|
||||
import { Wireplumber } from "./scripts/volume";
|
||||
import { handleArguments } from "./scripts/arg-handler";
|
||||
import { Runner } from "./runner/Runner";
|
||||
@@ -24,13 +25,13 @@ import { createRoot, getScope } from "ags";
|
||||
import { triggerOSD } from "./window/OSD";
|
||||
import { programArgs, programInvocationName } from "system";
|
||||
import { encoder, decoder } from "./scripts/utils";
|
||||
import { initPlayer } from "./scripts/media";
|
||||
|
||||
import GObject, { register } from "ags/gobject";
|
||||
import AstalNotifd from "gi://AstalNotifd";
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
import Gio from "gi://Gio?version=2.0";
|
||||
import Adw from "gi://Adw?version=1";
|
||||
import GdkPixbuf from "gi://GdkPixbuf?version=2.0";
|
||||
|
||||
|
||||
const runnerPlugins: Array<Runner.Plugin> = [
|
||||
@@ -48,8 +49,8 @@ Gtk.init();
|
||||
Adw.init();
|
||||
GLib.unsetenv("LD_PRELOAD");
|
||||
|
||||
@register({ GTypeName: "Shell" })
|
||||
export class Shell extends Gtk.Application {
|
||||
@register({ GTypeName: "Shell", Implements: [Gio.ActionGroup]})
|
||||
export class Shell extends Gtk.Application implements Gio.ActionMap {
|
||||
private static instance: Shell;
|
||||
|
||||
#loop!: GLib.MainLoop;
|
||||
@@ -77,7 +78,6 @@ export class Shell extends Gtk.Application {
|
||||
).map(path => {
|
||||
if(/^\$/.test(path)) {
|
||||
const env = GLib.getenv(path.replace(/^\$/, ""));
|
||||
|
||||
if(env === null)
|
||||
throw new Error(`Couldn't get environment variable: ${path}`);
|
||||
|
||||
@@ -106,6 +106,12 @@ export class Shell extends Gtk.Application {
|
||||
const e = _e as Error;
|
||||
console.error(`Error: couldn't load gresource! Stderr: ${e.message}\n${e.stack}`);
|
||||
}
|
||||
|
||||
// create action for gapplication to handle commands via dbus
|
||||
// (faster than running a remote instance to send arguments)
|
||||
// TODO: implement support for argument parsing through dbus
|
||||
const msgAction = Gio.SimpleAction.new("msg", null);
|
||||
this.add_action(msgAction);
|
||||
}
|
||||
|
||||
public static getDefault(): Shell {
|
||||
@@ -186,11 +192,13 @@ export class Shell extends Gtk.Application {
|
||||
private main(): void {
|
||||
this.#loop = GLib.MainLoop.new(null, false);
|
||||
|
||||
this.#connections.set(this, this.connect("shutdown", () => this.#scope.dispose()));
|
||||
createRoot(() => {
|
||||
console.log(`Colorshell: initializing`);
|
||||
createRoot((dispose) => {
|
||||
console.log(`Colorshell: Initializing things`);
|
||||
this.#connections.set(this, this.connect("shutdown", () => dispose()));
|
||||
this.#scope = getScope();
|
||||
|
||||
initPlayer();
|
||||
|
||||
Stylesheet.getDefault();
|
||||
|
||||
// Init clipboard module
|
||||
@@ -276,4 +284,4 @@ export const generalConfig = new Config<keyof typeof generalConfigDefaults,
|
||||
`${GLib.get_user_config_dir()}/colorshell/config.json`, generalConfigDefaults
|
||||
);
|
||||
|
||||
Shell.getDefault().runAsync([ programInvocationName, ...programArgs ]);
|
||||
Shell.getDefault().run([ programInvocationName, ...programArgs ]);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { timeout } from "ags/time";
|
||||
|
||||
import AstalHyprland from "gi://AstalHyprland";
|
||||
import AstalIO from "gi://AstalIO";
|
||||
import { Shell } from "../app";
|
||||
|
||||
|
||||
export namespace Runner {
|
||||
@@ -21,7 +22,7 @@ export type RunnerProps = {
|
||||
showResultsPlaceHolderOnStartup?: boolean;
|
||||
};
|
||||
|
||||
type Result = ResultWidgetProps;
|
||||
export type Result = ResultWidgetProps;
|
||||
|
||||
export interface Plugin {
|
||||
/** prefix to call the plugin. if undefined, will be triggered like applications plugin */
|
||||
@@ -244,7 +245,8 @@ export function openRunner(props: RunnerProps, placeholders?: Array<Result>): As
|
||||
heightRequest={props.height} exclusivity={Astal.Exclusivity.IGNORE} halign={Gtk.Align.CENTER}
|
||||
marginTop={(AstalHyprland.get_default().get_monitor(mon)?.height / 2) - (props.height! / 2)}
|
||||
valign={Gtk.Align.START} hexpand orientation={Gtk.Orientation.VERTICAL}
|
||||
$={() => {
|
||||
$={(self) => {
|
||||
self.set_application(Shell.getDefault());
|
||||
plugins.forEach(plugin =>
|
||||
plugin.init?.());
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createBinding, createComputed } from "ags";
|
||||
import { Runner } from "../Runner";
|
||||
import { player } from "../../widget/bar/Media";
|
||||
import { player } from "../../scripts/media";
|
||||
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { timeout } from "ags/time";
|
||||
import { Runner } from "../runner/Runner";
|
||||
import { showWorkspaceNumber } from "../widget/bar/Workspaces";
|
||||
import { playSystemBell } from "./utils";
|
||||
import { player, setPlayer } from "../widget/bar/Media";
|
||||
import { player, setPlayer } from "./media";
|
||||
import { generalConfig, Shell } from "../app";
|
||||
|
||||
import AstalIO from "gi://AstalIO";
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { createRoot, createState, onCleanup } from "ags";
|
||||
|
||||
import GObject from "ags/gobject";
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
|
||||
|
||||
export const dummyPlayer = {
|
||||
available: false,
|
||||
busName: "dummy_player",
|
||||
bus_name: "dummy_player"
|
||||
} as AstalMpris.Player;
|
||||
|
||||
export let [player, setPlayer] = createState(dummyPlayer);
|
||||
|
||||
let disposeFun: undefined|(() => void);
|
||||
|
||||
export function initPlayer(): void {
|
||||
if(disposeFun) {
|
||||
console.error("Media: cannot initialize, there's already an instance");
|
||||
return;
|
||||
}
|
||||
|
||||
createRoot((dispose) => {
|
||||
const connections = new Map<GObject.Object, Array<number>>();
|
||||
disposeFun = dispose;
|
||||
|
||||
if(AstalMpris.get_default().players)
|
||||
setPlayer(AstalMpris.get_default().players[0]);
|
||||
|
||||
connections.set(AstalMpris.get_default(), [
|
||||
AstalMpris.get_default().connect("player-added", (_, player) =>
|
||||
player.available && setPlayer(player)),
|
||||
|
||||
AstalMpris.get_default().connect("player-closed", (_, closedPlayer) => {
|
||||
const players = AstalMpris.get_default().players.filter(pl => pl?.available &&
|
||||
pl.busName !== closedPlayer.busName);
|
||||
|
||||
if(players.length > 0 && players[0]) {
|
||||
setPlayer(players[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
setPlayer(dummyPlayer);
|
||||
})
|
||||
]);
|
||||
|
||||
onCleanup(() => {
|
||||
connections.forEach((ids, obj) =>
|
||||
Array.isArray(ids) ?
|
||||
ids.forEach(id => obj.disconnect(id))
|
||||
: obj.disconnect(ids)
|
||||
);
|
||||
disposeFun = undefined;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export function disposePlayer(): void {
|
||||
if(disposeFun) {
|
||||
disposeFun();
|
||||
return;
|
||||
}
|
||||
|
||||
console.error("Media: Couldn't dispose player, there's no instance to dispose of");
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
@use "./colors";
|
||||
|
||||
.runner.main {
|
||||
.popup-window.runner * {
|
||||
$radius: 24px;
|
||||
|
||||
background: rgba($color: colors.$bg-primary, $alpha: .8);
|
||||
@@ -32,7 +32,7 @@
|
||||
}
|
||||
|
||||
& list {
|
||||
& .result {
|
||||
& listboxrow > * {
|
||||
padding: 10px;
|
||||
background: colors.$bg-primary;
|
||||
margin: 2px 0;
|
||||
|
||||
@@ -32,10 +32,11 @@ export function NotificationWidget({ notification, actionClicked, holdOnHover, s
|
||||
AstalNotifd.get_default().get_notification(notification)
|
||||
: notification;
|
||||
|
||||
const actions: Array<AstalNotifd.Action>|undefined = (notification instanceof AstalNotifd.Notification) ?
|
||||
notification.actions?.filter(a =>
|
||||
a.id.toLowerCase() !== "view" && a.label.toLowerCase() != "view"
|
||||
)
|
||||
const actions: Array<AstalNotifd.Action>|undefined = ((notification instanceof AstalNotifd.Notification) &&
|
||||
notification.actions && notification.actions.filter(a => Boolean(a)).length > 0) ?
|
||||
notification.actions?.filter(a =>
|
||||
a?.id?.toLowerCase() !== "view" && a?.label?.toLowerCase() != "view"
|
||||
)
|
||||
: undefined;
|
||||
|
||||
const conns: Map<GObject.Object, Array<number>> = new Map();
|
||||
|
||||
@@ -1,57 +1,32 @@
|
||||
import { Accessor, createBinding, createConnection, createState, onCleanup, With } from "ags";
|
||||
import { Accessor, createBinding, createConnection, onCleanup, With } from "ags";
|
||||
import { Gtk } from "ags/gtk4";
|
||||
import { Separator } from "../Separator";
|
||||
import { Windows } from "../../windows";
|
||||
import { Clipboard } from "../../scripts/clipboard";
|
||||
import { decoder, getPlayerIconFromBusName, variableToBoolean } from "../../scripts/utils";
|
||||
import { player, setPlayer } from "../../scripts/media";
|
||||
|
||||
import GObject from "ags/gobject";
|
||||
import AstalMpris from "gi://AstalMpris";
|
||||
import Pango from "gi://Pango?version=1.0";
|
||||
|
||||
|
||||
export const dummyPlayer = {
|
||||
available: false,
|
||||
busName: "dummy_player",
|
||||
bus_name: "dummy_player"
|
||||
} as AstalMpris.Player;
|
||||
export let [player, setPlayer] = createState(dummyPlayer);
|
||||
|
||||
export const Media = () => {
|
||||
const connections: Map<GObject.Object, Array<number>|number> = new Map();
|
||||
|
||||
if(AstalMpris.get_default().players[0])
|
||||
setPlayer(AstalMpris.get_default().players[0]);
|
||||
|
||||
onCleanup(() => connections.forEach((id, obj) =>
|
||||
Array.isArray(id) ?
|
||||
id.forEach(id => obj.disconnect(id))
|
||||
: obj.disconnect(id)
|
||||
));
|
||||
|
||||
connections.set(AstalMpris.get_default(), [
|
||||
AstalMpris.get_default().connect("player-added", (_, player) =>
|
||||
player.available && setPlayer(player)),
|
||||
|
||||
AstalMpris.get_default().connect("player-closed", (_, closedPlayer) => {
|
||||
const players = AstalMpris.get_default().players.filter(pl => pl?.available &&
|
||||
pl.busName !== closedPlayer.busName);
|
||||
|
||||
if(players.length > 0) {
|
||||
setPlayer(players[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
setPlayer(dummyPlayer);
|
||||
})
|
||||
]);
|
||||
|
||||
return <Gtk.Box class={"media"} visible={player((pl) => pl.available)}
|
||||
$={(self) => {
|
||||
const gestureClick = Gtk.GestureClick.new(),
|
||||
controllerMotion = Gtk.EventControllerMotion.new(),
|
||||
controllerScroll = Gtk.EventControllerScroll.new(
|
||||
Gtk.EventControllerScrollFlags.VERTICAL);
|
||||
Gtk.EventControllerScrollFlags.VERTICAL
|
||||
);
|
||||
|
||||
self.add_controller(gestureClick);
|
||||
self.add_controller(controllerMotion);
|
||||
|
||||
@@ -10,6 +10,7 @@ import GObject from "ags/gobject";
|
||||
import AstalBluetooth from "gi://AstalBluetooth";
|
||||
import AstalNetwork from "gi://AstalNetwork";
|
||||
import AstalWp from "gi://AstalWp";
|
||||
import { Shell } from "../../app";
|
||||
|
||||
|
||||
export const Status = () =>
|
||||
@@ -133,7 +134,7 @@ function StatusIcons() {
|
||||
: "preferences-system-notifications-symbolic")
|
||||
}
|
||||
/>
|
||||
<Gtk.Image iconName={"circle-filled-symbolic"} class={"notification-count"}
|
||||
<Gtk.Image gicon={Shell.getDefault().getGIcon("circle-filled-symbolic")} class={"notification-count"}
|
||||
visible={variableToBoolean(createBinding(Notifications.getDefault(), "history"))}
|
||||
/>
|
||||
</Gtk.Box>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { timeout } from "ags/time";
|
||||
import { Astal, Gtk } from "ags/gtk4";
|
||||
import { Clipboard } from "../../scripts/clipboard";
|
||||
import { getMediaUrl, player, setPlayer } from "../bar/Media";
|
||||
import { getMediaUrl } from "../bar/Media";
|
||||
import { player, setPlayer } from "../../scripts/media";
|
||||
import { createBinding, For } from "ags";
|
||||
import { pathToURI, variableToBoolean } from "../../scripts/utils";
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { FocusedClient } from "../widget/bar/FocusedClient";
|
||||
import { Apps } from "../widget/bar/Apps";
|
||||
import { Clock } from "../widget/bar/Clock";
|
||||
import { Status } from "../widget/bar/Status";
|
||||
import { Media } from "../widget/bar/Media";
|
||||
|
||||
|
||||
export const Bar = (mon: number) => {
|
||||
@@ -29,6 +30,7 @@ export const Bar = (mon: number) => {
|
||||
$type="center">
|
||||
|
||||
<Clock />
|
||||
<Media />
|
||||
</Gtk.Box>
|
||||
<Gtk.Box class={"widgets-right"} homogeneous={false}
|
||||
spacing={widgetSpacing} halign={Gtk.Align.END}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { Astal, Gtk } from "ags/gtk4";
|
||||
|
||||
import { Gtk } from "ags/gtk4";
|
||||
import { Separator } from "../widget/Separator";
|
||||
import { PopupWindow } from "../widget/PopupWindow";
|
||||
import { BigMedia } from "../widget/center-window/BigMedia";
|
||||
import { time } from "../scripts/utils";
|
||||
import { player } from "../widget/bar/Media";
|
||||
import { time, variableToBoolean } from "../scripts/utils";
|
||||
import { createBinding } from "ags";
|
||||
|
||||
import AstalMpris from "gi://AstalMpris?version=0.1";
|
||||
|
||||
export const CenterWindow = (mon: number) =>
|
||||
<PopupWindow namespace={"center-window"} marginTop={10} monitor={mon}
|
||||
@@ -13,8 +14,7 @@ export const CenterWindow = (mon: number) =>
|
||||
<Gtk.Box class={"center-window-container"} spacing={6}>
|
||||
<Gtk.Box class={"left"} orientation={Gtk.Orientation.VERTICAL}>
|
||||
<Gtk.Box class={"datetime"} orientation={Gtk.Orientation.VERTICAL}
|
||||
halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER}
|
||||
vexpand={true}>
|
||||
halign={Gtk.Align.CENTER} valign={Gtk.Align.CENTER} vexpand>
|
||||
|
||||
<Gtk.Label class={"time"} label={time(t => t.format("%H:%M")!)} />
|
||||
<Gtk.Label class={"date"} label={time(d => d.format("%A, %B %d")!)} />
|
||||
@@ -27,8 +27,10 @@ export const CenterWindow = (mon: number) =>
|
||||
</Gtk.Box>
|
||||
|
||||
<Separator orientation={Gtk.Orientation.HORIZONTAL} cssColor="gray"
|
||||
margin={5} spacing={8} alpha={.3} visible={player(pl => pl.available)}
|
||||
margin={5} spacing={8} alpha={.3} visible={variableToBoolean(
|
||||
createBinding(AstalMpris.get_default(), "players")
|
||||
)}
|
||||
/>
|
||||
<BigMedia />
|
||||
</Gtk.Box>
|
||||
</PopupWindow> as Astal.Window;
|
||||
</PopupWindow>;
|
||||
|
||||
@@ -28,8 +28,10 @@ export const FloatingNotifications = (mon: number) =>
|
||||
<NotificationWidget notification={notif} showTime={false}
|
||||
actionClose={() => Notifications.getDefault().removeNotification(notif)}
|
||||
holdOnHover={false} actionClicked={() => {
|
||||
const viewAction = notif.actions.filter(action =>
|
||||
action.label.toLowerCase() === "view")?.[0];
|
||||
const viewAction = notif.actions.filter(a =>
|
||||
a.id.toLowerCase() === "view" ||
|
||||
a.label.toLowerCase() === "view"
|
||||
)?.[0];
|
||||
|
||||
viewAction && notif.invoke(viewAction.id);
|
||||
}}
|
||||
|
||||
Reference in New Issue
Block a user