diff --git a/src/cli/index.ts b/src/cli/index.ts index 943bf99..5748bb5 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,5 +1,6 @@ import { Scope } from "ags"; import { createScopedConnection, decoder, encoder } from "../modules/utils"; +import { showWorkspaceNumber } from "../window/bar/widgets/Workspaces"; import windows from "./modules/windows"; import volume from "./modules/volume"; @@ -9,6 +10,7 @@ import Gio from "gi://Gio?version=2.0"; import GLib from "gi://GLib?version=2.0"; +/** cli implementation for colorshell */ export namespace Cli { let rootScope: Scope; let initialized: boolean = false; @@ -27,6 +29,14 @@ export namespace Cli { type: "out" }; } + }, + { + name: "peek-workspace-num", + help: "peek the workspace numbers in the workspace indicator. (optional: time in millis)", + onCalled: () => { + showWorkspaceNumber(true); + return "Peeking workspace IDs..."; + } } ], arguments: [ @@ -214,13 +224,33 @@ export namespace Cli { ); } - for(let i = 0; i < args.length; i++) { - const arg = args[i]; + function handleCommandArguments(cmd: Module|Command, args: Array, index: number, printFun: (out: Output) => void): void { + const argNameRegEx = /^--/, argAliasRegEx = /^-/; + let argName: string; - if(i === 0) { + if(args[index].startsWith("--")) { } } + + const firstFoundMod = modules.filter(mod => mod.prefix === args[0])[0]; + mod = firstFoundMod ?? modules[0]; + + if(!mod) { + print({ + content: `No command module found with the name ${args[0]}!`, + type: "err" + }); + return; + } + + for(let i = 1; i < args.length; i++) { + const arg = args[i]; + + if(/^-/.test(arg)) { + handleCommandArguments(command ?? mod, args, i, print); + continue; + } } function outputToString(out: Output): string { diff --git a/src/modules/compositors/index.ts b/src/modules/compositors/index.ts index d5b6e44..26be802 100644 --- a/src/modules/compositors/index.ts +++ b/src/modules/compositors/index.ts @@ -1,8 +1,11 @@ import { CompositorHyprland } from "./hyprland"; -import GObject, { getter, gtype, register } from "ags/gobject"; +import GObject, { getter, gtype, property, register } from "ags/gobject"; import GLib from "gi://GLib?version=2.0"; + +export default Compositors; + /** WIP modular implementation of a system that supports implementing * a variety of Wayland Compositors * @todo implement more general compositor info + a lot of stuff @@ -14,7 +17,6 @@ export namespace Compositors { export class Monitor extends GObject.Object { #width: number; #height: number; - #scaling: number; @getter(Number) get width() { return this.#width; } @@ -22,15 +24,15 @@ export namespace Compositors { @getter(Number) get height() { return this.#height; } - @getter(Number) - get scaling() { return this.#scaling; } + @property(Number) + scaling: number; constructor(width: number, height: number, scaling: number = 1) { super(); this.#width = width; this.#height = height; - this.#scaling = scaling; + this.scaling = scaling; } } @@ -49,7 +51,6 @@ export namespace Compositors { super(); this.#monitor = monitor; - this.notify("monitor"); this.#id = id; } } @@ -110,10 +111,9 @@ export namespace Compositors { if(props.position !== undefined) this.#position = props.position; - if(props.initialClass !== undefined) - this.#initialClass = props.initialClass; - else - this.#initialClass = props.class; + this.#initialClass = props.initialClass !== undefined ? + props.initialClass + : props.class; } } diff --git a/src/window/control-center/widgets/tiles/Network.tsx b/src/window/control-center/widgets/tiles/Network.tsx index 2a5c233..bb22325 100644 --- a/src/window/control-center/widgets/tiles/Network.tsx +++ b/src/window/control-center/widgets/tiles/Network.tsx @@ -1,85 +1,153 @@ -import { execAsync } from "ags/process"; import { Tile } from "./Tile"; +import { execAsync } from "ags/process"; import { PageNetwork } from "../pages/Network"; import { tr } from "../../../../i18n/intl"; import { TilesPages } from "../tiles"; -import { Gtk } from "ags/gtk4"; -import { createBinding, createComputed, With } from "ags"; +import { Accessor, createBinding, createComputed } from "ags"; +import { secureBaseBinding } from "../../../../modules/utils"; import AstalNetwork from "gi://AstalNetwork"; +import { Notifications } from "../../../../modules/notifications"; -export const TileNetwork = () => - +const { WIFI, WIRED } = AstalNetwork.Primary, + { CONNECTED, CONNECTING } = AstalNetwork.Internet; - {([primary, wired, wifi]: [AstalNetwork.Primary, AstalNetwork.Wired, AstalNetwork.Wifi]) => { - if(primary === AstalNetwork.Primary.WIFI) { - return ssid ? ssid : (() => { - switch(internet) { - case AstalNetwork.Internet.CONNECTED: - return tr("connected"); - case AstalNetwork.Internet.DISCONNECTED: - return tr("disconnected"); - case AstalNetwork.Internet.CONNECTING: - return tr("connecting") + "..."; - } - })() - )} onEnabled={() => wifi.set_enabled(true)} - onDisabled={() => wifi.set_enabled(false)} - hasArrow onClicked={() => TilesPages?.toggle(PageNetwork)} - icon={"network-wireless-signal-excellent-symbolic"} - state={createBinding(wifi, "enabled")} - /> +const wiredInternet = secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wired"), + "internet", + AstalNetwork.Internet.DISCONNECTED +) as Accessor; - } else if(primary === AstalNetwork.Primary.WIRED) { - return { - switch(internet) { - case AstalNetwork.Internet.CONNECTED: - return tr("connected"); - case AstalNetwork.Internet.DISCONNECTED: - return tr("disconnected"); - case AstalNetwork.Internet.CONNECTING: - return tr("connecting") + "..."; - } - })} - hasArrow onEnabled={() => execAsync("nmcli n on")} - onDisabled={() => execAsync("nmcli n off")} - onClicked={() => TilesPages?.toggle(PageNetwork)} - icon={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => { - switch(internet) { - case AstalNetwork.Internet.CONNECTED: - return "network-wired-symbolic"; - case AstalNetwork.Internet.DISCONNECTED: - return "network-wired-disconnected-symbolic"; - } +const wifiInternet = secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wifi"), + "internet", + AstalNetwork.Internet.DISCONNECTED +) as Accessor; - return "network-wired-no-route-symbolic"; - })} - state={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => - internet === AstalNetwork.Internet.CONNECTING - || internet === AstalNetwork.Internet.CONNECTED - )} - /> - } - - return execAsync("nmcli n on")} - onDisabled={() => execAsync("nmcli n off")} - hasArrow onClicked={() => TilesPages?.toggle(PageNetwork)} - icon={"network-wired-disconnected-symbolic"} - state={createBinding(wired, "internet").as((internet: AstalNetwork.Internet) => - internet === AstalNetwork.Internet.CONNECTING || internet === AstalNetwork.Internet.CONNECTED)} - /> - }} - -; +const wifiSSID = secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wifi"), + "ssid", + "Unknown" +) as Accessor; + +const wifiIcon = secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wifi"), + "iconName", + "network-wireless-symbolic" +); + +const wiredIcon = secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wired"), + "iconName", + "network-wired-symbolic" +); + +const primary = createBinding(AstalNetwork.get_default(), "primary"); + +export const TileNetwork = () => + { + switch(primary) { + case WIFI: + if(wiInternet === CONNECTED) + return wiSSID; + + return tr("control_center.tiles.network.wireless"); + + case WIRED: + return tr("control_center.tiles.network.wired"); + } + + return tr("control_center.tiles.network.network"); + })} + onClicked={() => TilesPages?.toggle(PageNetwork)} + icon={createComputed([ + primary, + wifiIcon, + wiredIcon + ], (primary, wifiIcon, wiredIcon) => { + switch(primary) { + case WIFI: + return wifiIcon; + + case WIRED: + return wiredIcon; + } + + return "network-wired-no-route-symbolic"; + })} + state={createComputed([ + primary, + secureBaseBinding( + createBinding(AstalNetwork.get_default(), "wifi"), + "enabled", + false + ), + wiredInternet.as(internet => internet === CONNECTED || internet === CONNECTING) + ], (primary, wifiEnabled, wiredEnabled) => { + switch(primary) { + case WIFI: + return wifiEnabled; + + case WIRED: + return wiredEnabled; + } + + return false; + })} + description={createComputed([ + primary, + wifiInternet, + wiredInternet + ], (primary, wifiInternet, wiredInternet) => { + switch(primary) { + case WIFI: + return internetToTranslatedString(wifiInternet); + + case WIRED: + return internetToTranslatedString(wiredInternet); + } + + return tr("disconnected"); + })} + onToggled={(self, state) => { + switch(AstalNetwork.get_default().primary) { + case WIFI: + AstalNetwork.get_default().wifi.set_enabled(state); + return; + + case WIRED: + (state ? + execAsync("nmcli n off") + : execAsync("nmcli n on") + ).catch(e => { + Notifications.getDefault().sendNotification({ + appName: "network", + summary: "Couldn't turn off network", + body: `Turning off networking with nmcli failed: ${ + e?.message ?? "(no error message)"}` + }); + }); + return; + } + + // disable if no device available + self.state = false; + }} + />; + + +function internetToTranslatedString(internet: AstalNetwork.Internet): string { + switch(internet) { + case AstalNetwork.Internet.CONNECTED: + return tr("connected"); + case AstalNetwork.Internet.CONNECTING: + return tr("connecting") + "..."; + } + + return tr("disconnected"); +} diff --git a/src/window/control-center/widgets/tiles/Tile.tsx b/src/window/control-center/widgets/tiles/Tile.tsx index 61b08e9..232e679 100644 --- a/src/window/control-center/widgets/tiles/Tile.tsx +++ b/src/window/control-center/widgets/tiles/Tile.tsx @@ -30,7 +30,7 @@ export class Tile extends Gtk.Box { public hasArrow: boolean = false; declare $signals: Gtk.Box.SignalSignatures & { - "toggled": (_state: boolean) => void; + "toggled": (state: boolean) => void; "enabled": () => void; "disabled": () => void; "clicked": () => void; diff --git a/src/window/floating-notifications/index.tsx b/src/window/floating-notifications/index.tsx index 8c7a995..9259863 100644 --- a/src/window/floating-notifications/index.tsx +++ b/src/window/floating-notifications/index.tsx @@ -16,34 +16,41 @@ export const FloatingNotifications = (mon: number) => generalConfig.bindProperty("notifications.position_h", "string"), generalConfig.bindProperty("notifications.position_v", "string") ]).as(([posH, posV]) => { - let horizontal: Astal.WindowAnchor = Astal.WindowAnchor.RIGHT, - vertical: Astal.WindowAnchor = Astal.WindowAnchor.TOP; + const pos: Array = []; switch(posH) { case "left": - horizontal = Astal.WindowAnchor.LEFT; + pos.push(Astal.WindowAnchor.LEFT); break; case "center": - horizontal = Astal.WindowAnchor.LEFT | Astal.WindowAnchor.RIGHT; + pos.push(Astal.WindowAnchor.LEFT); + pos.push(Astal.WindowAnchor.RIGHT); break; case "right": - horizontal = Astal.WindowAnchor.RIGHT; + pos.push(Astal.WindowAnchor.RIGHT); break; } switch(posV) { case "top": - vertical = Astal.WindowAnchor.TOP; + pos.push(Astal.WindowAnchor.TOP); break; case "center": - vertical = Astal.WindowAnchor.TOP | Astal.WindowAnchor.BOTTOM; + pos.push(Astal.WindowAnchor.TOP); + pos.push(Astal.WindowAnchor.BOTTOM); break; case "bottom": - vertical = Astal.WindowAnchor.BOTTOM; + pos.push(Astal.WindowAnchor.BOTTOM); break; } - return horizontal | vertical; + let finalPos: Astal.WindowAnchor; + + pos.forEach(pos => finalPos = (finalPos !== undefined ? + finalPos | pos + : pos)); + + return finalPos!; })} exclusivity={Astal.Exclusivity.NORMAL} resizable={false} widthRequest={450}>