diff --git a/ags/runner/plugins/apps.ts b/ags/runner/plugins/apps.ts index 914fdc5..ab423e0 100644 --- a/ags/runner/plugins/apps.ts +++ b/ags/runner/plugins/apps.ts @@ -1,6 +1,6 @@ import { ResultWidget, ResultWidgetProps } from "../../widget/runner/ResultWidget"; import AstalApps from "gi://AstalApps"; -import { cleanExec, getAstalApps, updateApps } from "../../scripts/apps"; +import { execApp, getAstalApps, updateApps } from "../../scripts/apps"; import { Runner } from "../Runner"; import { Astal } from "astal/gtk3"; @@ -15,7 +15,7 @@ export const PluginApps = { title: app.get_name(), description: app.get_description(), icon: Astal.Icon.lookup_icon(app.iconName) ? app.iconName : "application-x-executable-symbolic", - onClick: () => cleanExec(app) + onClick: () => execApp(app) } as ResultWidgetProps) ); } diff --git a/ags/runner/plugins/clipboard.ts b/ags/runner/plugins/clipboard.ts index 67c838e..0e10582 100644 --- a/ags/runner/plugins/clipboard.ts +++ b/ags/runner/plugins/clipboard.ts @@ -12,12 +12,12 @@ export const PluginClipboard = { if(Clipboard.getDefault().history.length < 1) return new ResultWidget({ icon: "edit-paste-symbolic", - title: "No clipboard items found!", - description: "When something is copied, it'll be shown right here!" + title: "Clipboard is empty", + description: "Copy something and it will be shown right here!" } as ResultWidgetProps); return Clipboard.getDefault().history.filter(item => // not the best way to search, but it works - Runner.regExMatch(search, item.id.toString()) || Runner.regExMatch(search, item.preview)).map((item) => + Runner.regExMatch(search, item.id) || Runner.regExMatch(search, item.preview)).map((item) => new ResultWidget({ icon: new Widget.Label({ label: item.id.toString(), diff --git a/ags/scripts/apps.ts b/ags/scripts/apps.ts index ae1fb77..0e3fdbe 100644 --- a/ags/scripts/apps.ts +++ b/ags/scripts/apps.ts @@ -2,8 +2,12 @@ import { Astal } from "astal/gtk3"; import AstalApps from "gi://AstalApps"; import AstalHyprland from "gi://AstalHyprland"; +import { execAsync } from "astal"; + const astalApps: AstalApps.Apps = new AstalApps.Apps(); +const uwsmIsActive: boolean = await execAsync("uwsm check is-active").then((stdout) => + /hyprland/gi.test(stdout)).catch(() => false); let appsList: Array = astalApps.get_list(); export function getApps(): Array { @@ -19,8 +23,14 @@ export function getAstalApps(): AstalApps.Apps { return astalApps; } -export function cleanExec(app: AstalApps.Application): void { - AstalHyprland.get_default().dispatch("exec", app.executable.replace(/(%f|%F|%u|%U|%i|%c|%k)/g, "")); +/** handles running with uwsm if it's installed */ +export function execApp(app: AstalApps.Application|string, dispatchExecArgs?: string) { + const executable = (typeof app === "string") ? app + : app.executable.replace(/(%f|%F|%u|%U|%i|%c|%k)/g, ""); + + AstalHyprland.get_default().dispatch("exec", + `${dispatchExecArgs ? `${dispatchExecArgs} ` : ""}${uwsmIsActive ? "uwsm app -- " : ""}${executable}` + ); } export function getAppsByName(appName: string): (Array|undefined) { diff --git a/ags/scripts/nightlight.ts b/ags/scripts/nightlight.ts index 419ee0a..b60f6d1 100644 --- a/ags/scripts/nightlight.ts +++ b/ags/scripts/nightlight.ts @@ -22,11 +22,10 @@ class NightLight extends GObject.Object { public get gamma() { return this.#gamma; } public set gamma(newValue: number) { this.setGamma(newValue); } - @property(Number) - public get maxTemperature() { return 20000; } - - @property(Number) - public get maxGamma() { return 100; } + public readonly maxTemperature = 20000; + public readonly minTemperature = 1000; + public readonly identityTemperature = 6000; + public readonly maxGamma = 100; @property(Boolean) public get identity() { return this.#identity; } @@ -72,7 +71,7 @@ class NightLight extends GObject.Object { return this.instance; } - private async setTemperature(value: number): Promise { + private setTemperature(value: number): void { if(value === this.temperature) return; if(value > this.maxTemperature || value < 1000) { @@ -93,7 +92,7 @@ class NightLight extends GObject.Object { )); } - private async setGamma(value: number) { + private setGamma(value: number): void { if(value === this.gamma) return; if(value > this.maxGamma || value < 0) { @@ -114,14 +113,14 @@ class NightLight extends GObject.Object { )); } - private applyIdentity(): void { + public applyIdentity(): void { if(this.#identity) return; this.#prevGamma = this.#gamma; this.#prevTemperature = this.#temperature; this.#identity = true; - this.temperature = 6000; + this.temperature = this.identityTemperature; this.gamma = this.maxGamma; } @@ -129,8 +128,8 @@ class NightLight extends GObject.Object { if(!this.#identity) return; this.#identity = false; - this.setTemperature(this.#prevTemperature ?? 1000); - this.setGamma(this.#prevGamma ?? 100); + this.setTemperature(this.#prevTemperature ?? this.identityTemperature); + this.setGamma(this.#prevGamma ?? this.maxGamma); this.#prevTemperature = null; this.#prevGamma = null; diff --git a/ags/scripts/stylesheet.ts b/ags/scripts/stylesheet.ts index 09cf01f..ee235b3 100644 --- a/ags/scripts/stylesheet.ts +++ b/ags/scripts/stylesheet.ts @@ -12,11 +12,11 @@ export class Stylesheet { "./style.scss" ]; - public compileSass(): void { + public async compileSass(): Promise { console.log("Stylesheet: Compiling Sass"); - exec(`bash -c "sass ${this.#styles.map(style => `-I ${style}`).join('\s') - } ${this.#outputPath.get_path()!}/style.css"`); + exec(`bash -c "sass ${this.#styles.map(style => `-I ${style}`).join('\s')} ${ + this.#outputPath.get_path()!}/style.css"`); } public async reapply(cssFilePath: string): Promise { @@ -37,8 +37,10 @@ export class Stylesheet { } public async compileApply(): Promise { - this.compileSass(); - this.reapply(this.#outputPath.get_path()! + "/style.css"); + await this.compileSass().catch((err: Gio.IOErrorEnum) => + console.error(`Stylesheet: An Error occurred and Sass couldn't be compiled. Stderr:\n${err.message ? + `\t${err.message}\n` : ""}${err.stack}\n`) + ).then(() => this.reapply(this.#outputPath.get_path()! + "/style.css")); } public static getDefault(): Stylesheet { diff --git a/ags/style/_logout-menu.scss b/ags/style/_logout-menu.scss index e8c6b2f..41e4637 100644 --- a/ags/style/_logout-menu.scss +++ b/ags/style/_logout-menu.scss @@ -1,6 +1,8 @@ @use "./colors"; .logout-menu { + background: rgba($color: colors.$bg-translucent-primary, $alpha: .4); + .top { .time { font-size: 128px; diff --git a/ags/style/_wal.scss b/ags/style/_wal.scss index e6286f0..7294f94 100644 --- a/ags/style/_wal.scss +++ b/ags/style/_wal.scss @@ -1,26 +1,26 @@ // SCSS Variables // Generated by 'wal' -$wallpaper: "/home/joaov/wallpapers/Kagamine Rin Yellow Tapes.png"; +$wallpaper: "/home/joaov/wallpapers/Kita Street.jpeg"; // Special -$background: #190b14; -$foreground: #c5c2c4; -$cursor: #c5c2c4; +$background: #131a1b; +$foreground: #c4c5c6; +$cursor: #c4c5c6; // Colors -$color0: #190b14; -$color1: #905027; -$color2: #685345; -$color3: #766b0c; -$color4: #a78117; -$color5: #ad9527; -$color6: #425c6e; -$color7: #998e95; -$color8: #6e5a67; -$color9: #C06B35; -$color10: #8B6F5D; -$color11: #9E8F11; -$color12: #DFAC1F; -$color13: #E7C735; -$color14: #597B93; -$color15: #c5c2c4; +$color0: #131a1b; +$color1: #765236; +$color2: #7e6c46; +$color3: #a07f4c; +$color4: #556c6d; +$color5: #75817c; +$color6: #918d7e; +$color7: #90989b; +$color8: #5d7171; +$color9: #9E6E48; +$color10: #A9905E; +$color11: #D6AA66; +$color12: #729092; +$color13: #9CACA6; +$color14: #C2BDA9; +$color15: #c4c5c6; diff --git a/ags/widget/bar/Media.ts b/ags/widget/bar/Media.ts index bf67c06..77aa2fb 100644 --- a/ags/widget/bar/Media.ts +++ b/ags/widget/bar/Media.ts @@ -4,10 +4,18 @@ import AstalMpris from "gi://AstalMpris"; import { getSymbolicIcon } from "../../scripts/apps"; import { Separator, SeparatorProps } from "../Separator"; import { Windows } from "../../windows"; -import { Clipboard } from "../../scripts/clipboard"; +<<<<<<< ryo +======= + +const playerIcons = { + spotify: "spotify-symbolic", + mpv: "mpv-symbolic", + Clapper: "com.github.rafostar.Clapper-symbolic" +}; + +>>>>>>> ryo export function Media(): Gtk.Widget { - const connections: Array = []; const mediaControlsRevealer: Widget.Revealer = new Widget.Revealer({ @@ -26,11 +34,9 @@ export function Media(): Gtk.Widget { icon: "edit-paste-symbolic" } as Widget.IconProps), tooltipText: "Copy link to Clipboard", - visible: bind(players[0], "metadata").as((meta) => - Boolean(meta["xesam:url"]?.get_string()[0])), - onClick: () => Clipboard.getDefault().copyAsync( - players[0].metadata["xesam:url"].get_string()[0] - ) + visible: bind(players[0], "metadata").as((metadata) => + metadata["xesam:url"]?.get_string()[0] != null), + onClick: () => console.log(players[0].metadata["xesam:url"]?.get_string()[0]!) } as Widget.ButtonProps), new Widget.Button({ className: "previous", diff --git a/ags/widget/control-center/Pages.ts b/ags/widget/control-center/Pages.ts index ae1b9a4..ef108d2 100644 --- a/ags/widget/control-center/Pages.ts +++ b/ags/widget/control-center/Pages.ts @@ -73,7 +73,6 @@ class Pages extends Widget.Box { this.#page = undefined; timeout(this.#transDuration, () => { - pageRevealer.ref(); this.remove(pageRevealer); pageRevealer.destroy(); diff --git a/ags/widget/control-center/QuickActions.ts b/ags/widget/control-center/QuickActions.ts index 58218f2..b3b40fc 100644 --- a/ags/widget/control-center/QuickActions.ts +++ b/ags/widget/control-center/QuickActions.ts @@ -1,8 +1,8 @@ -import { exec, execAsync, GLib, Variable } from "astal"; +import { exec, GLib, Variable } from "astal"; import { Gtk, Widget } from "astal/gtk3"; -import AstalHyprland from "gi://AstalHyprland"; import { Windows } from "../../windows"; import { Wallpaper } from "../../scripts/wallpaper"; +import { execApp } from "../../scripts/apps"; function LockButton(): Widget.Button { @@ -12,7 +12,7 @@ function LockButton(): Widget.Button { } as Widget.IconProps), onClick: () => { Windows.close("control-center"); - AstalHyprland.get_default().dispatch("exec", "hyprlock"); + execApp("hyprlock"); } } as Widget.ButtonProps) } @@ -22,10 +22,10 @@ function ColorPickerButton(): Widget.Button { image: new Widget.Icon({ icon: "color-select-symbolic" } as Widget.IconProps), - onClick: () => AstalHyprland.get_default().dispatch( - "exec", - "sh $HOME/.config/hypr/scripts/color-picker.sh" - ) + onClick: () => { + Windows.close("control-center"); + execApp("sh $HOME/.config/hypr/scripts/color-picker.sh"); + } } as Widget.ButtonProps) } @@ -36,7 +36,7 @@ function ScreenshotButton(): Widget.Button { } as Widget.IconProps), onClick: () => { Windows.close("control-center"); - execAsync(`sh ${GLib.get_user_config_dir()}/hypr/scripts/screenshot.sh`); + execApp(`sh ${GLib.get_user_config_dir()}/hypr/scripts/screenshot.sh`); } } as Widget.ButtonProps); } @@ -58,7 +58,10 @@ function LogoutButton(): Widget.Button { image: new Widget.Icon({ icon: "system-shutdown-symbolic" } as Widget.IconProps), - onClick: () => Windows.open("logout-menu") + onClick: () => { + Windows.close("control-center"); + Windows.open("logout-menu"); + } } as Widget.ButtonProps); } diff --git a/ags/widget/control-center/pages/Bluetooth.ts b/ags/widget/control-center/pages/Bluetooth.ts index 2db0444..46f442c 100644 --- a/ags/widget/control-center/pages/Bluetooth.ts +++ b/ags/widget/control-center/pages/Bluetooth.ts @@ -3,10 +3,10 @@ import { Gtk, Widget } from "astal/gtk3"; import AstalBluetooth from "gi://AstalBluetooth"; import { Page, PageButton } from "./Page"; import { tr } from "../../../i18n/intl"; -import AstalHyprland from "gi://AstalHyprland"; import { Windows } from "../../../windows"; import { Notifications } from "../../../scripts/notifications"; import AstalNotifd from "gi://AstalNotifd"; +import { execApp } from "../../../scripts/apps"; export const BluetoothPage: (() => Page) = () => new Page({ id: "bluetooth", @@ -42,7 +42,7 @@ export const BluetoothPage: (() => Page) = () => new Page({ title: tr("control_center.pages.more_settings"), onClick: () => { Windows.close("control-center"); - AstalHyprland.get_default().dispatch("exec", "[float; animation slide right] overskride"); + execApp("overskride", "[float; animation slide right]"); } }], spacing: 2, diff --git a/ags/widget/control-center/pages/Microphone.ts b/ags/widget/control-center/pages/Microphone.ts index 8444612..3d101cc 100644 --- a/ags/widget/control-center/pages/Microphone.ts +++ b/ags/widget/control-center/pages/Microphone.ts @@ -21,7 +21,7 @@ export function PageMicrophone(): Page { className: bind(microphone, "isDefault").as(isDefault => isDefault ? "default" : ""), icon: bind(microphone, "icon").as(icon => Astal.Icon.lookup_icon(icon) ? icon : "audio-input-microphone-symbolic"), - title: bind(microphone, "name").as(name => name ?? "Microphone"), + title: bind(microphone, "description").as(desc => desc ?? "Microphone"), onClick: () => microphone.set_is_default(true), endWidget: new Widget.Icon({ icon: "object-select-symbolic", diff --git a/ags/widget/control-center/pages/Network.ts b/ags/widget/control-center/pages/Network.ts index ca0176c..3626cdd 100644 --- a/ags/widget/control-center/pages/Network.ts +++ b/ags/widget/control-center/pages/Network.ts @@ -4,8 +4,8 @@ import AstalNetwork from "gi://AstalNetwork"; import { bind } from "astal"; import NM from "gi://NM"; import { Windows } from "../../../windows"; -import AstalHyprland from "gi://AstalHyprland"; import { tr } from "../../../i18n/intl"; +import { execApp } from "../../../scripts/apps"; export const PageNetwork: (() => Page) = () => new Page({ id: "network", @@ -27,7 +27,7 @@ export const PageNetwork: (() => Page) = () => new Page({ title: tr("control_center.pages.more_settings"), onClick: () => { Windows.close("control-center"); - AstalHyprland.get_default().dispatch("exec", "[animationstyle gnomed] nm-connection-editor"); + execApp("nm-connection-editor", "[animationstyle gnomed]"); } }], children: [ @@ -60,10 +60,10 @@ export const PageNetwork: (() => Page) = () => new Page({ } as Widget.IconProps), onClick: () => { Windows.close("control-center"); - AstalHyprland.get_default().dispatch("exec", - `[animationstyle gnomed; float] nm-connection-editor --edit ${ - dev.activeConnection?.connection.get_uuid() - }`); + execApp( + `nm-connection-editor --edit ${dev.activeConnection?.connection.get_uuid()}`, + "[animationstyle gnomed; float]" + ); } } as Widget.ButtonProps) ] diff --git a/ags/widget/control-center/pages/NightLight.ts b/ags/widget/control-center/pages/NightLight.ts index 8c54223..c0d1047 100644 --- a/ags/widget/control-center/pages/NightLight.ts +++ b/ags/widget/control-center/pages/NightLight.ts @@ -25,7 +25,7 @@ export const PageNightLight: (() => Page) = () => new Page({ value: bind(NightLight.getDefault(), "temperature"), tooltipText: bind(NightLight.getDefault(), "temperature").as((temp) => `${temp}K`), min: 1000, - max: bind(NightLight.getDefault(), "maxTemperature"), + max: NightLight.getDefault().maxTemperature, onDragged: (slider) => NightLight.getDefault().temperature = (Math.floor(slider.value)), } as Widget.SliderProps), @@ -42,7 +42,7 @@ export const PageNightLight: (() => Page) = () => new Page({ addSliderMarksFromMinMax(slider, 5, "{}%"); }, value: bind(NightLight.getDefault(), "gamma"), - max: bind(NightLight.getDefault(), "maxGamma"), + max: NightLight.getDefault().maxGamma, tooltipText: bind(NightLight.getDefault(), "gamma").as((gamma) => `${gamma}%`), onDragged: (slider) => NightLight.getDefault().gamma = (Math.floor(slider.value)), diff --git a/ags/widget/control-center/pages/Page.ts b/ags/widget/control-center/pages/Page.ts index 5098ea2..a30f15a 100644 --- a/ags/widget/control-center/pages/Page.ts +++ b/ags/widget/control-center/pages/Page.ts @@ -172,7 +172,7 @@ class Page extends Widget.Box { } } -export function PageButton(props: { +export function PageButton({ onDestroy, ...props }: { className?: string | Binding; icon?: string | Binding; title: string | Binding; @@ -185,7 +185,7 @@ export function PageButton(props: { tooltipMarkup?: string | Binding; }): Gtk.Widget { return new Widget.Box({ - onDestroy: props.onDestroy, + onDestroy, children: [ new Widget.Button({ onClick: props.onClick, @@ -202,17 +202,26 @@ export function PageButton(props: { className: "icon", icon: props.icon, visible: props.icon, + hexpand: false, css: "font-size: 20px; margin-right: 6px;" } as Widget.IconProps), new Widget.Box({ orientation: Gtk.Orientation.VERTICAL, - expand: true, + hexpand: true, + vexpand: false, children: [ new Widget.Label({ className: "title", xalign: 0, + // truncating is not working, so I had to do this + label: (props.title instanceof Binding) ? + props.title.as((title) => + `${title.substring(0, 35)}${ + title.length > 35 ? '…' : ""}`) + : `${props.title.substring(0, 35)}${ + props.title.length > 35 ? '…' : ""}`, + tooltipText: props.title, truncate: true, - label: props.title } as Widget.LabelProps), new Widget.Label({ className: "description", @@ -230,6 +239,7 @@ export function PageButton(props: { visible: (props.endWidget instanceof Binding) ? props.endWidget.as(Boolean) : props.endWidget, + halign: Gtk.Align.END, child: props.endWidget } as Widget.BoxProps) ] diff --git a/ags/widget/control-center/pages/Sound.ts b/ags/widget/control-center/pages/Sound.ts index 17b8a8d..cd0d9fc 100644 --- a/ags/widget/control-center/pages/Sound.ts +++ b/ags/widget/control-center/pages/Sound.ts @@ -27,7 +27,7 @@ export function PageSound(): Page { className: bind(speaker, "isDefault").as(isDefault => isDefault ? "default" : ""), icon: bind(speaker, "icon").as(icon => Astal.Icon.lookup_icon(icon)? icon : "audio-card-symbolic"), - title: speaker.name ?? "Speaker", + title: bind(speaker, "description").as(desc => desc ?? "Speaker"), onClick: () => speaker.set_is_default(true), endWidget: new Widget.Icon({ icon: "object-select-symbolic", diff --git a/ags/widget/control-center/tiles/NightLight.ts b/ags/widget/control-center/tiles/NightLight.ts index 55238d6..dbbf1bc 100644 --- a/ags/widget/control-center/tiles/NightLight.ts +++ b/ags/widget/control-center/tiles/NightLight.ts @@ -7,19 +7,16 @@ import { TilesPages } from "../Tiles"; import { isInstalled } from "../../../scripts/utils"; import { Widget } from "astal/gtk3"; -export const TileNightLight = () => isInstalled("hyprsunset") ? - Tile({ +export const TileNightLight = () => isInstalled("hyprsunset") ? Tile({ title: tr("control_center.tiles.night_light.title"), icon: "weather-clear-night-symbolic", description: Variable.derive([ bind(NightLight.getDefault(), "temperature"), bind(NightLight.getDefault(), "gamma") - ], (temp, gamma) => - (temp === 6000 ? tr("control_center.tiles.night_light.default_desc") - : `${temp}K`) + (gamma < NightLight.getDefault().maxGamma ? - ` (${gamma}%)` : "") + ], (temp, gamma) => `${temp === NightLight.getDefault().identityTemperature ? + tr("control_center.tiles.night_light.default_desc") : `${temp}K`} ${ + gamma < NightLight.getDefault().maxGamma ? `(${gamma}%)` : ""}` )(), - iconSize: 16, onToggledOff: () => NightLight.getDefault().identity = true, onToggledOn: () => NightLight.getDefault().identity = false, enableOnClickMore: true, diff --git a/ags/widget/control-center/tiles/Tile.ts b/ags/widget/control-center/tiles/Tile.ts index 5261829..8e0af31 100644 --- a/ags/widget/control-center/tiles/Tile.ts +++ b/ags/widget/control-center/tiles/Tile.ts @@ -18,13 +18,15 @@ export type TileProps = { } export function Tile(props: TileProps): (() => Gtk.Widget) { - const toggled = new Variable(props.toggleState instanceof Binding ? - (props.toggleState.get() || false) : (props.toggleState || false)); - - let subscription: () => void; + const subs: Array<() => void> = []; + const toggled = new Variable(((props.toggleState instanceof Binding) ? + props.toggleState.get() + : props.toggleState) ?? false); if(props?.toggleState instanceof Binding) - subscription = props.toggleState.subscribe(val => toggled.set(val || false)); + subs.push(props.toggleState.subscribe((state) => + toggled.set(state ?? false) + )); return () => new Widget.Box({ className: (props.className instanceof Binding) ? @@ -37,15 +39,15 @@ export function Tile(props: TileProps): (() => Gtk.Widget) { }` )() : toggled().as((state: boolean) => - `tile ${state ? "toggled" : ""} ${ - props.onClickMore ? "has-more" : "" + `tile${state ? " toggled" : ""}${ + props.onClickMore ? " has-more" : "" }` ), expand: true, visible: props.visible, onDestroy: () => { + subs.map(sub => sub?.()); props.onDestroy?.(); - subscription?.(); }, children: [ new Widget.Button({ diff --git a/ags/window/AppsWindow.ts b/ags/window/AppsWindow.ts index 7c1b890..1e9a903 100644 --- a/ags/window/AppsWindow.ts +++ b/ags/window/AppsWindow.ts @@ -1,6 +1,6 @@ import { GObject, Variable } from "astal"; import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; -import { cleanExec, getAppIcon, getApps, getAstalApps } from "../scripts/apps"; +import { execApp, getAppIcon, getApps, getAstalApps } from "../scripts/apps"; import AstalApps from "gi://AstalApps"; import { PopupWindow } from "../widget/PopupWindow"; @@ -83,7 +83,7 @@ export const AppsWindow = (mon: number): (Widget.Window) => { button.set_can_focus(false); const openFun = () => { - cleanExec(app); + execApp(app); window.close(); }; diff --git a/ags/window/LogoutMenu.ts b/ags/window/LogoutMenu.ts index ce043ad..e4254a6 100644 --- a/ags/window/LogoutMenu.ts +++ b/ags/window/LogoutMenu.ts @@ -1,8 +1,10 @@ import { Astal, Gdk, Gtk, Widget } from "astal/gtk3"; import { getDateTime } from "../scripts/time"; -import { exec, execAsync, GLib } from "astal"; +import { exec, execAsync, Gio, GLib } from "astal"; import { AskPopup } from "../widget/AskPopup"; import { Windows } from "../windows"; +import { Notifications } from "../scripts/notifications"; +import AstalNotifd from "gi://AstalNotifd"; const { TOP, LEFT, RIGHT, BOTTOM } = Astal.WindowAnchor; @@ -99,8 +101,32 @@ export const LogoutMenu = (mon: number) => new Widget.Window({ title: "Log out", text: "Are you sure you want to log out? Your session will be ended.", onAccept: () => { - exec(`sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"`); - execAsync(`sh -c "loginctl terminate-user ${GLib.getenv("USER") || "$USER"}"`); + execAsync( + `sh "${GLib.getenv("XDG_CONFIG_HOME")}/hypr/scripts/save-hyprsunset.sh"` + ).finally(() => + execAsync(`hyprctl dispatch exit`).catch((err: Gio.IOErrorEnum) => + Notifications.getDefault().sendNotification({ + appName: "colorshell", + summary: "Couldn't exit Hyprland", + body: `An error occurred and colorshell couldn't exit Hyprland. Stderr: \n${ + err.message ? `${err.message}\n` : ""}${err.stack}`, + urgency: AstalNotifd.Urgency.NORMAL, + actions: [{ + text: "Report Issue on colorshell", + onAction: () => execAsync( + `xdg-open https://github.com/retrozinndev/colorshell/issues/new` + ).catch((err: Gio.IOErrorEnum) => + Notifications.getDefault().sendNotification({ + appName: "colorshell", + summary: "Couldn't open link", + body: `Do you have \`xdg-utils\` installed? Stderr: \n${ + err.message ? `${err.message}\n` : ""}${err.stack}` + }) + ) + }] + }) + ) + ); } }) } as Widget.ButtonProps), diff --git a/hypr/scripts/color-picker.sh b/hypr/scripts/color-picker.sh index 8febeb7..6dd06a4 100644 --- a/hypr/scripts/color-picker.sh +++ b/hypr/scripts/color-picker.sh @@ -5,14 +5,14 @@ function send_notification() { } # Check if user has hyprpicker installed -if ! [[ -f /bin/hyprpicker ]]; then +if [[ -z $(command -v hyprpicker) ]]; then send_notification "An error occurred" "Looks like you don't have hyprpicker installed! Try installing it before using the Color Picker tool." exit 1 fi -selected_color=$(hyprpicker | tail -n 1 | xargs) +selected_color=$(hyprpicker | tail -n 1 | xargs | sed -e 's/ //g') -if ! [[ -z $selected_color ]]; then +if [[ ! -z "$selected_color" ]] && [[ ! "$selected_color" == " " ]]; then wl-copy $selected_color send_notification "Selected Color" "The selected color is $selected_color, it was also copied to your clipboard!" fi diff --git a/hypr/scripts/exec.sh b/hypr/scripts/exec.sh new file mode 100644 index 0000000..d0ddf68 --- /dev/null +++ b/hypr/scripts/exec.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# This script executes the provided program with UWSM +# if in usage or launches it normally with hyprctl. +# --------------- +# Licensed under the MIT License +# Made by retrozinndev (João Dias) +# From: https://github.com/retrozinndev/colorshell + + +if uwsm check is-active; then + hyprctl dispatch exec "uwsm app -- $@" > /dev/null + exit 0 +fi + +hyprctl dispatch exec "$@" > /dev/null diff --git a/hypr/shell/autostart.conf b/hypr/shell/autostart.conf index f2f4cea..458e956 100644 --- a/hypr/shell/autostart.conf +++ b/hypr/shell/autostart.conf @@ -6,16 +6,16 @@ exec-once = systemctl enable --user --now hyprpolkitagent # Hyprland's PolKit exec-once = systemctl enable --user --now hypridle exec-once = systemctl enable --user --now gnome-keyring-daemon -exec-once = wl-paste --type text --watch cliphist store -exec-once = wl-paste --type image --watch cliphist store +exec-once = $exec wl-paste --type text --watch cliphist store +exec-once = $exec wl-paste --type image --watch cliphist store # Tools exec-once = systemctl enable --user --now hyprsunset exec-once = systemctl enable --user --now hyprpaper # Scripts -exec-once = sh $XDG_CONFIG_HOME/hypr/scripts/gen-pywal.sh -exec-once = sleep 3 && sh $XDG_CONFIG_HOME/hypr/scripts/load-hyprsunset.sh # wait some time to actually set the filters +exec-once = $exec sh $XDG_CONFIG_HOME/hypr/scripts/gen-pywal.sh +exec-once = $exec sleep 3 && sh $XDG_CONFIG_HOME/hypr/scripts/load-hyprsunset.sh # wait some time to actually set the filters # Shell -exec-once = ags run +exec-once = $exec ags run diff --git a/hypr/shell/bindings.conf b/hypr/shell/bindings.conf index 996802f..72d8a85 100644 --- a/hypr/shell/bindings.conf +++ b/hypr/shell/bindings.conf @@ -1,26 +1,28 @@ # color-shell specific configuration, please don't modify unless you know what you're doing! +# `astal` and some `.*ctl` commands don't need $exec (uwsm), since it's just some process communication + bind = $mainMod, SPACE, exec, $menu bind = $mainMod, F11, fullscreen -bind = , Print, exec, sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh -bind = $mainMod, Print, exec, sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh full +bind = , Print, exec, $exec sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh +bind = $mainMod, Print, exec, $exec sh $XDG_CONFIG_HOME/hypr/scripts/screenshot.sh full -# Test-only bind, restarts colorshell -bind = $mainMod, F7, exec, ags request reload +# restarts colorshell +bind = $mainMod, F7, exec, astal reload -bind = $mainMod, K, exec, $terminal +bind = $mainMod, K, exec, $exec $terminal bind = $mainMod, Q, killactive -bind = $mainMod, E, exec, $fm +bind = $mainMod, E, exec, $exec $fm bind = $mainMod, F, togglefloating bind = $mainMod, P, pseudo, bind = $mainMod, J, togglesplit bind = $mainMod, N, exec, astal toggle control-center bind = $mainMod, M, exec, astal toggle center-window -bind = $mainMod, L, exec, hyprlock -bind = $mainMod, V, exec, astal runner '>' || sh $XDG_CONFIG_HOME/hypr/scripts/clipboard-menu.sh +bind = $mainMod, L, exec, $exec hyprlock +bind = $mainMod, V, exec, astal runner '>' || $exec sh $XDG_CONFIG_HOME/hypr/scripts/clipboard-menu.sh bind = $mainMod, W, exec, astal runner '##' # bind = $mainMod, $mainMod_L, exec, astal toggle apps-window diff --git a/hypr/shell/environment.conf b/hypr/shell/environment.conf index 091d622..ccce967 100644 --- a/hypr/shell/environment.conf +++ b/hypr/shell/environment.conf @@ -25,5 +25,5 @@ env = QT_QPA_PLATFORMTHEME, qt5ct env = QT_AUTO_SCREEN_SCALE_FACTOR, 1 # Others -env = ADW_DISABLE_PORTAL, 1 # Fixes prefer-dark theme setting in some flatpak apps +env = ADW_DISABLE_PORTAL, 1 # Fixes prefer-dark setting in some gtk flatpak apps env = WALLPAPERS, $HOME/wallpapers diff --git a/hypr/shell/rules.conf b/hypr/shell/rules.conf index 0e44001..5c8e9b4 100644 --- a/hypr/shell/rules.conf +++ b/hypr/shell/rules.conf @@ -28,6 +28,7 @@ windowrule = animation gnomed, class:hyprpolkitagent windowrule = animation slide right, class:org.pulseaudio.pavucontrol windowrule = animation slide right, class:io.github.kaii_lb.Overskride windowrule = animation gnomed, class:xdg-desktop-portal.* +windowrule = animation gnomed, class:hyprsysteminfo layerrule = animation fade, selection layerrule = animation fade, hyprpicker diff --git a/hypr/shell/variables.conf b/hypr/shell/variables.conf index de75150..1bdf451 100644 --- a/hypr/shell/variables.conf +++ b/hypr/shell/variables.conf @@ -6,8 +6,10 @@ ############### # Wiki: https://wiki.hyprland.org/Hypr-Ecosystem/hyprlang#defining-variables +# Use this variable to execute apps dinamically (runs with uwsm if being used by compositor) +$exec = sh $XDG_CONFIG_HOME/hypr/scripts/exec.sh + $mainMod = SUPER $terminal = kitty $fm = nautilus -$menu = astal runner || anyrun -$dmenu = anyrun --plugins libstdin.so +$menu = astal runner