mirror of
https://github.com/zephrynis/nix-flake.git
synced 2026-02-18 20:21:53 +00:00
feat: make AGS colorshell configuration fully declarative
- Add complete colorshell v2.0.3 configuration to home/ags-config/ - Disable runner plugin and NightLight tile (incompatible with NixOS) - Customize SCSS with full opacity (no transparency) - Add dark pale blue color scheme in home/pywal-colors/ - Configure Papirus-Dark icon theme via home-manager - Make ~/.config/ags/ immutable and managed by Nix store - Auto-deploy pywal colors to ~/.cache/wal/colors.json All AGS configuration is now reproducible and version controlled.
This commit is contained in:
69
home/ags-config/modules/compositors/hyprland.ts
Normal file
69
home/ags-config/modules/compositors/hyprland.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { Compositors } from ".";
|
||||
import { register } from "ags/gobject";
|
||||
import { createRoot, getScope, Scope } from "ags";
|
||||
import { createScopedConnection } from "../utils";
|
||||
|
||||
|
||||
import AstalHyprland from "gi://AstalHyprland";
|
||||
|
||||
|
||||
type Event = "activewindow" | "activewindowv2"
|
||||
| "workspace" | "workspacev2"
|
||||
| "focusedmon" | "focusedmonv2";
|
||||
|
||||
@register({ GTypeName: "CompositorHyprland" })
|
||||
export class CompositorHyprland extends Compositors.Compositor {
|
||||
#scope: Scope;
|
||||
hyprland: AstalHyprland.Hyprland;
|
||||
|
||||
protected _focusedClient: Compositors.Client | null = null;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
try {
|
||||
this.hyprland = AstalHyprland.get_default();
|
||||
} catch(e) {
|
||||
throw new Error(`Couldn't initialize CompositorHyprland: ${e}`);
|
||||
}
|
||||
|
||||
this.#scope = createRoot(() => {
|
||||
createScopedConnection(
|
||||
this.hyprland, "event", (e, args) => {
|
||||
switch(e as Event) {
|
||||
case "activewindowv2":
|
||||
const address = args;
|
||||
const clients = AstalHyprland.get_default().clients;
|
||||
const focusedClient = clients.filter(c =>
|
||||
c.address === address
|
||||
)[0];
|
||||
|
||||
if(focusedClient) {
|
||||
this._focusedClient = new Compositors.Client({
|
||||
address: address,
|
||||
class: focusedClient.class ?? "",
|
||||
initialClass: focusedClient.initialClass ?? "",
|
||||
mapped: focusedClient.mapped,
|
||||
position: [focusedClient.x, focusedClient.y],
|
||||
title: focusedClient.title ?? ""
|
||||
});
|
||||
|
||||
this.notify("focused-client");
|
||||
return;
|
||||
}
|
||||
|
||||
this._focusedClient = null;
|
||||
this.notify("focused-client");
|
||||
break;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return getScope();
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_dispose(): void {
|
||||
this.#scope.dispose();
|
||||
}
|
||||
}
|
||||
162
home/ags-config/modules/compositors/index.ts
Normal file
162
home/ags-config/modules/compositors/index.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import { CompositorHyprland } from "./hyprland";
|
||||
import GObject, { getter, gtype, property, register } from "ags/gobject";
|
||||
|
||||
import GLib from "gi://GLib?version=2.0";
|
||||
|
||||
|
||||
/** WIP modular implementation of a system that supports implementing
|
||||
* a variety of Wayland Compositors
|
||||
* @todo implement more general compositor info + a lot of stuff
|
||||
* */
|
||||
export namespace Compositors {
|
||||
let compositor: Compositor|null = null;
|
||||
|
||||
@register({ GTypeName: "CompositorMonitor" })
|
||||
export class Monitor extends GObject.Object {
|
||||
#width: number;
|
||||
#height: number;
|
||||
|
||||
@getter(Number)
|
||||
get width() { return this.#width; }
|
||||
|
||||
@getter(Number)
|
||||
get height() { return this.#height; }
|
||||
|
||||
@property(Number)
|
||||
scaling: number;
|
||||
|
||||
constructor(width: number, height: number, scaling: number = 1) {
|
||||
super();
|
||||
|
||||
this.#width = width;
|
||||
this.#height = height;
|
||||
this.scaling = scaling;
|
||||
}
|
||||
}
|
||||
|
||||
@register({ GTypeName: "CompositorWorkspace" })
|
||||
export class Workspace extends GObject.Object {
|
||||
#id: number;
|
||||
#monitor: Monitor;
|
||||
|
||||
@getter(Number)
|
||||
get id() { return this.#id; }
|
||||
|
||||
@getter(Monitor)
|
||||
get monitor() { return this.#monitor; }
|
||||
|
||||
constructor(monitor: Monitor, id: number = 0) {
|
||||
super();
|
||||
|
||||
this.#monitor = monitor;
|
||||
this.#id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@register({ GTypeName: "CompositorClient" })
|
||||
export class Client extends GObject.Object {
|
||||
readonly #address: string|null = null;
|
||||
#initialClass: string;
|
||||
#class: string;
|
||||
#title: string = "";
|
||||
#mapped: boolean = true;
|
||||
#position: [number, number] = [0, 0];
|
||||
#xwayland: boolean = false;
|
||||
|
||||
@getter(gtype<string|null>(String))
|
||||
get address() { return this.#address; }
|
||||
|
||||
@getter(String)
|
||||
get title() { return this.#title; }
|
||||
|
||||
@getter(String)
|
||||
get class() { return this.#class; }
|
||||
|
||||
@getter(String)
|
||||
get initialClass() { return this.#initialClass; }
|
||||
|
||||
@getter(gtype<[number, number]>(Array))
|
||||
get position() { return this.#position; }
|
||||
|
||||
@getter(Boolean)
|
||||
get xwayland() { return this.#xwayland; }
|
||||
|
||||
@getter(Boolean)
|
||||
get mapped() { return this.#mapped; }
|
||||
|
||||
constructor(props: {
|
||||
address?: string;
|
||||
title?: string;
|
||||
mapped?: boolean;
|
||||
class: string;
|
||||
initialClass?: string;
|
||||
/** [x, y] */
|
||||
position?: [number, number];
|
||||
}) {
|
||||
super();
|
||||
|
||||
this.#class = props.class;
|
||||
|
||||
if(props.title !== undefined)
|
||||
this.#title = props.title;
|
||||
|
||||
if(props.mapped !== undefined)
|
||||
this.#mapped = props.mapped;
|
||||
|
||||
if(props.address !== undefined)
|
||||
this.#address = props.address;
|
||||
|
||||
if(props.position !== undefined)
|
||||
this.#position = props.position;
|
||||
|
||||
this.#initialClass = props.initialClass !== undefined ?
|
||||
props.initialClass
|
||||
: props.class;
|
||||
}
|
||||
}
|
||||
|
||||
@register({ GTypeName: "Compositor" })
|
||||
export class Compositor extends GObject.Object {
|
||||
protected _workspaces: Array<Workspace> = [];
|
||||
protected _focusedClient: Client|null = null;
|
||||
|
||||
@getter(Array<Workspace>)
|
||||
get workspaces() { return this._workspaces; }
|
||||
|
||||
@getter(gtype<Client|null>(Client))
|
||||
get focusedClient() { return this._focusedClient; }
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export function getDefault(): Compositor {
|
||||
if(!compositor)
|
||||
throw new Error("Compositors haven't been initialized correctly, please call `Compositors.init()` before calling any method in `Compositors`");
|
||||
|
||||
return compositor;
|
||||
}
|
||||
|
||||
|
||||
/** Uses the XDG_CURRENT_DESKTOP variable to detect running compositor's name.
|
||||
* ---
|
||||
* @returns running wayland compositor's name (lowercase) or `undefined` if variable's not set */
|
||||
export function getName(): string|undefined {
|
||||
return GLib.getenv("XDG_CURRENT_DESKTOP")?.toLowerCase() ?? undefined;
|
||||
}
|
||||
|
||||
/** initialize colorshell's wayland compositor implementation abstraction.
|
||||
* when called, and if it's implemented, sets the default compositor to an equivalent implementation for the current desktop(checks from XDG_CURRENT_DESKTOP) */
|
||||
export function init(): void {
|
||||
switch(Compositors.getName()) {
|
||||
case "hyprland":
|
||||
compositor = new CompositorHyprland();
|
||||
break;
|
||||
|
||||
default:
|
||||
console.error(`This compositor(${Compositors.getName()}) is not yet implemented to colorshell. Please contribute by implementing it if you can! :)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user