diff --git a/.config/quickshell/ReloadPopup.qml b/.config/quickshell/ReloadPopup.qml index c3f0aab9..eb19cbd9 100644 --- a/.config/quickshell/ReloadPopup.qml +++ b/.config/quickshell/ReloadPopup.qml @@ -97,6 +97,7 @@ Scope { // A progress bar on the bottom of the screen, showing how long until the // popup is removed. Rectangle { + z: 2 id: bar color: failed ? "#ff93000A" : "#ff0C1F13" anchors.bottom: parent.bottom @@ -109,9 +110,9 @@ Scope { id: anim target: bar property: "width" - from: rect.width + from: rect.width - bar.anchors.margins * 2 to: 0 - duration: failed ? 10000 : 800 + duration: failed ? 10000 : 1000 onFinished: popupLoader.active = false // Pause the animation when the mouse is hovering over the popup, @@ -120,6 +121,18 @@ Scope { paused: mouseArea.containsMouse } } + // Its bg + Rectangle { + z: 1 + id: bar_bg + color: failed ? "#30af1b25" : "#4027643e" + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.margins: 10 + height: 5 + radius: 9999 + width: rect.width - bar.anchors.margins * 2 + } // We could set `running: true` inside the animation, but the width of the // rectangle might not be calculated yet, due to the layout. diff --git a/.config/quickshell/assets/icons/ai-openai-symbolic.svg b/.config/quickshell/assets/icons/ai-openai-symbolic.svg new file mode 120000 index 00000000..c9ee0b32 --- /dev/null +++ b/.config/quickshell/assets/icons/ai-openai-symbolic.svg @@ -0,0 +1 @@ +openai-symbolic.svg \ No newline at end of file diff --git a/.config/quickshell/assets/icons/arch-symbolic.svg b/.config/quickshell/assets/icons/arch-symbolic.svg new file mode 100644 index 00000000..7de9094e --- /dev/null +++ b/.config/quickshell/assets/icons/arch-symbolic.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/cachyos-symbolic.svg b/.config/quickshell/assets/icons/cachyos-symbolic.svg new file mode 100644 index 00000000..4a9db19a --- /dev/null +++ b/.config/quickshell/assets/icons/cachyos-symbolic.svg @@ -0,0 +1,318 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg b/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg new file mode 100644 index 00000000..bd48d3c9 --- /dev/null +++ b/.config/quickshell/assets/icons/cloudflare-dns-symbolic.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/crosshair-symbolic.svg b/.config/quickshell/assets/icons/crosshair-symbolic.svg new file mode 100644 index 00000000..22967493 --- /dev/null +++ b/.config/quickshell/assets/icons/crosshair-symbolic.svg @@ -0,0 +1,65 @@ + + + + + + + ionicons-v5_logos + + + + ionicons-v5_logos + + + + + + diff --git a/.config/quickshell/assets/icons/debian-symbolic.svg b/.config/quickshell/assets/icons/debian-symbolic.svg new file mode 100644 index 00000000..252f8533 --- /dev/null +++ b/.config/quickshell/assets/icons/debian-symbolic.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/deepseek-symbolic.svg b/.config/quickshell/assets/icons/deepseek-symbolic.svg new file mode 100644 index 00000000..029e1266 --- /dev/null +++ b/.config/quickshell/assets/icons/deepseek-symbolic.svg @@ -0,0 +1,47 @@ + + + + + + + + + diff --git a/.config/quickshell/assets/icons/desktop-symbolic.svg b/.config/quickshell/assets/icons/desktop-symbolic.svg new file mode 100644 index 00000000..04f7a3b5 --- /dev/null +++ b/.config/quickshell/assets/icons/desktop-symbolic.svg @@ -0,0 +1,4 @@ + + + + diff --git a/.config/quickshell/assets/icons/endeavouros-symbolic.svg b/.config/quickshell/assets/icons/endeavouros-symbolic.svg new file mode 100644 index 00000000..3be4cc40 --- /dev/null +++ b/.config/quickshell/assets/icons/endeavouros-symbolic.svg @@ -0,0 +1,96 @@ + + + + + EndeavourOS Logo + + + + image/svg+xml + + EndeavourOS Logo + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/fedora-symbolic.svg b/.config/quickshell/assets/icons/fedora-symbolic.svg new file mode 100644 index 00000000..1a4e8c87 --- /dev/null +++ b/.config/quickshell/assets/icons/fedora-symbolic.svg @@ -0,0 +1,38 @@ + + + + + + + diff --git a/.config/quickshell/assets/icons/flatpak-symbolic.svg b/.config/quickshell/assets/icons/flatpak-symbolic.svg new file mode 100644 index 00000000..0c2bf628 --- /dev/null +++ b/.config/quickshell/assets/icons/flatpak-symbolic.svg @@ -0,0 +1,52 @@ + + + + + Flatpak + + + + + Flatpak + + + + diff --git a/.config/quickshell/assets/icons/github-symbolic.svg b/.config/quickshell/assets/icons/github-symbolic.svg new file mode 100644 index 00000000..c1c9f19c --- /dev/null +++ b/.config/quickshell/assets/icons/github-symbolic.svg @@ -0,0 +1,40 @@ + + + + + + diff --git a/.config/quickshell/assets/icons/google-gemini-symbolic.svg b/.config/quickshell/assets/icons/google-gemini-symbolic.svg new file mode 100644 index 00000000..9de741be --- /dev/null +++ b/.config/quickshell/assets/icons/google-gemini-symbolic.svg @@ -0,0 +1,56 @@ + + + + + + + ionicons-v5_logos + + + + + ionicons-v5_logos + + + + diff --git a/.config/quickshell/assets/icons/linux-symbolic.svg b/.config/quickshell/assets/icons/linux-symbolic.svg new file mode 100644 index 00000000..63f9c7e5 --- /dev/null +++ b/.config/quickshell/assets/icons/linux-symbolic.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/microsoft-symbolic.svg b/.config/quickshell/assets/icons/microsoft-symbolic.svg new file mode 100644 index 00000000..b90cfc63 --- /dev/null +++ b/.config/quickshell/assets/icons/microsoft-symbolic.svg @@ -0,0 +1,54 @@ + + + + + + + + + diff --git a/.config/quickshell/assets/icons/nixos-symbolic.svg b/.config/quickshell/assets/icons/nixos-symbolic.svg new file mode 100644 index 00000000..b697b0d1 --- /dev/null +++ b/.config/quickshell/assets/icons/nixos-symbolic.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/ollama-symbolic.svg b/.config/quickshell/assets/icons/ollama-symbolic.svg new file mode 100644 index 00000000..01454815 --- /dev/null +++ b/.config/quickshell/assets/icons/ollama-symbolic.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + diff --git a/.config/quickshell/assets/icons/openai-symbolic.svg b/.config/quickshell/assets/icons/openai-symbolic.svg new file mode 100644 index 00000000..8ffc912a --- /dev/null +++ b/.config/quickshell/assets/icons/openai-symbolic.svg @@ -0,0 +1,38 @@ + + + + + + diff --git a/.config/quickshell/assets/icons/openrouter-symbolic.svg b/.config/quickshell/assets/icons/openrouter-symbolic.svg new file mode 100644 index 00000000..32aaaf50 --- /dev/null +++ b/.config/quickshell/assets/icons/openrouter-symbolic.svg @@ -0,0 +1,39 @@ + + + + + + diff --git a/.config/quickshell/assets/icons/ubuntu-symbolic.svg b/.config/quickshell/assets/icons/ubuntu-symbolic.svg new file mode 100644 index 00000000..07746c9f --- /dev/null +++ b/.config/quickshell/assets/icons/ubuntu-symbolic.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.config/quickshell/assets/images/default_wallpaper.png b/.config/quickshell/assets/images/default_wallpaper.png new file mode 100644 index 00000000..77d890c2 Binary files /dev/null and b/.config/quickshell/assets/images/default_wallpaper.png differ diff --git a/.config/quickshell/modules/common/Appearance.qml b/.config/quickshell/modules/common/Appearance.qml index b290c2a9..bbbf733f 100644 --- a/.config/quickshell/modules/common/Appearance.qml +++ b/.config/quickshell/modules/common/Appearance.qml @@ -114,10 +114,14 @@ Singleton { property color colOnLayer2: m3colors.m3onSurface; property color colLayer3: mix(m3colors.m3surfaceContainerHigh, m3colors.m3onSurface, 0.96); property color colOnLayer3: m3colors.m3onSurface; + property color colLayer1Hover: mix(colLayer1, colOnLayer1, 0.85); + property color colLayer1Active: mix(colLayer1, colOnLayer1, 0.70); property color colLayer2Hover: mix(colLayer2, colOnLayer2, 0.90); property color colLayer2Active: mix(colLayer2, colOnLayer2, 0.80); property color colLayer3Hover: mix(colLayer3, colOnLayer3, 0.90); property color colLayer3Active: mix(colLayer3, colOnLayer3, 0.80); + property color colPrimaryHover: mix(m3colors.m3primary, colLayer1Hover, 0.7) + property color colPrimaryActive: mix(m3colors.m3primary, colLayer1Active, 0.4) } rounding: QtObject { diff --git a/.config/quickshell/modules/common/ConfigOptions.qml b/.config/quickshell/modules/common/ConfigOptions.qml index 93fa413a..216a7dfd 100644 --- a/.config/quickshell/modules/common/ConfigOptions.qml +++ b/.config/quickshell/modules/common/ConfigOptions.qml @@ -20,4 +20,8 @@ Singleton { property int updateInterval: 3000 } + property QtObject hacks: QtObject { + property int arbitraryRaceConditionDelay: 10 + } + } diff --git a/.config/quickshell/modules/common/widgets/CustomIcon.qml b/.config/quickshell/modules/common/widgets/CustomIcon.qml new file mode 100644 index 00000000..1e8ab368 --- /dev/null +++ b/.config/quickshell/modules/common/widgets/CustomIcon.qml @@ -0,0 +1,24 @@ +import QtQuick +import Qt.labs.platform +import Quickshell +import Quickshell.Widgets + +Item { + id: root + + property string source: "" + property string iconFolder: StandardPaths.standardLocations(StandardPaths.ConfigLocation)[0] + "/quickshell/assets/icons" // The folder to check first + width: 30 + height: 30 + + IconImage { + id: iconImage + anchors.fill: parent + source: { + if (iconFolder && iconFolder + "/" + root.source) { + return iconFolder + "/" + root.source + } + return root.source + } + } +} diff --git a/.config/quickshell/modules/sidebarRight/QuickToggleButton.qml b/.config/quickshell/modules/sidebarRight/QuickToggleButton.qml new file mode 100644 index 00000000..0c3cb82c --- /dev/null +++ b/.config/quickshell/modules/sidebarRight/QuickToggleButton.qml @@ -0,0 +1,33 @@ +import "../common" +import "../common/widgets" +import QtQuick +import QtQuick.Controls + +Button { + id: button + + property bool toggled + + signal clicked() + + implicitWidth: 40 + implicitHeight: 40 + onClicked: { + } + + background: Rectangle { + anchors.fill: parent + radius: Appearance.rounding.full + color: toggled ? + (button.down ? Appearance.colors.colPrimaryActive : button.hovered ? Appearance.colors.colPrimaryHover : Appearance.m3colors.m3primary) : + (button.down ? Appearance.colors.colLayer1Active : button.hovered ? Appearance.colors.colLayer1Hover : Appearance.transparentize(Appearance.colors.colLayer1Hover, 1)) + + MaterialSymbol { + anchors.centerIn: parent + text: "coffee" + color: toggled ? Appearance.m3colors.m3onPrimary : Appearance.colors.colOnLayer1 + } + + } + +} diff --git a/.config/quickshell/modules/sidebarRight/SidebarRight.qml b/.config/quickshell/modules/sidebarRight/SidebarRight.qml index b26d59ee..4e846336 100644 --- a/.config/quickshell/modules/sidebarRight/SidebarRight.qml +++ b/.config/quickshell/modules/sidebarRight/SidebarRight.qml @@ -5,14 +5,14 @@ import QtQuick.Controls import QtQuick.Layouts import Quickshell.Io import Quickshell +import Quickshell.Widgets import Quickshell.Wayland import Quickshell.Hyprland import Qt5Compat.GraphicalEffects Scope { - id: bar - - readonly property int sidebarWidth: Appearance.sizes.sidebarWidth + property int sidebarWidth: Appearance.sizes.sidebarWidth + property int sidebarPadding: 15 Variants { id: sidebarVariants @@ -29,6 +29,7 @@ Scope { exclusiveZone: 0 width: sidebarWidth WlrLayershell.namespace: "quickshell:sidebarRight" + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive color: "transparent" anchors { @@ -38,9 +39,29 @@ Scope { } HyprlandFocusGrab { - active: sidebarRoot.visible id: grab windows: [ sidebarRoot ] + active: false + onCleared: () => { + // sidebarRoot.visible = false + if (!active) sidebarRoot.visible = false + } + } + + Connections { + target: sidebarRoot + function onVisibleChanged() { + delayedGrabTimer.start() + } + } + + Timer { + id: delayedGrabTimer + interval: ConfigOptions.hacks.arbitraryRaceConditionDelay + repeat: false + onTriggered: { + grab.active = sidebarRoot.visible + } } // Background @@ -60,6 +81,70 @@ Scope { event.accepted = true; // Prevent further propagation of the event } } + + ColumnLayout { + anchors.centerIn: parent + height: parent.height - sidebarPadding * 2 + width: parent.width - sidebarPadding * 2 + spacing: sidebarPadding + + RowLayout { + Layout.fillHeight: false + spacing: 10 + Layout.margins: 10 + Layout.topMargin: 10 + + CustomIcon { + width: 25 + height: 25 + source: SystemInfo.distroIcon + } + + StyledText { + font.pointSize: Appearance.font.pointSize.normal + color: Appearance.colors.colOnLayer0 + text: `Uptime: ${DateTime.uptime}` + } + + Item { + Layout.fillHeight: true + } + + + } + + Rectangle { + Layout.alignment: Qt.AlignHCenter + Layout.fillHeight: false + radius: Appearance.rounding.full + color: Appearance.colors.colLayer1 + implicitWidth: sidebarQuickControlsRow.implicitWidth + 10 + implicitHeight: sidebarQuickControlsRow.implicitHeight + 10 + + + RowLayout { + id: sidebarQuickControlsRow + anchors.fill: parent + anchors.margins: 5 + spacing: 5 + Rectangle { + width: 40 + height: 40 + color: "#77000000" + radius: Appearance.rounding.full + } + + QuickToggleButton { + toggled: false + } + + } + } + + Item { + Layout.fillHeight: true + } + } } // Shadow diff --git a/.config/quickshell/scripts/wayland-idle-inhibitor.py b/.config/quickshell/scripts/wayland-idle-inhibitor.py new file mode 100755 index 00000000..9bdaabb0 --- /dev/null +++ b/.config/quickshell/scripts/wayland-idle-inhibitor.py @@ -0,0 +1,86 @@ +#!/usr/bin/env -S\_/bin/sh\_-xc\_"source\_\$(eval\_echo\_\$ILLOGICAL_IMPULSE_VIRTUAL_ENV)/bin/activate&&exec\_python\_-E\_"\$0"\_"\$@"" + +# From https://github.com/stwa/wayland-idle-inhibitor +# License: WTFPL Version 2 + +import sys +from dataclasses import dataclass +from signal import SIGINT, SIGTERM, signal +from threading import Event +import setproctitle + +from pywayland.client.display import Display +from pywayland.protocol.idle_inhibit_unstable_v1.zwp_idle_inhibit_manager_v1 import ( + ZwpIdleInhibitManagerV1, +) +from pywayland.protocol.wayland.wl_compositor import WlCompositor +from pywayland.protocol.wayland.wl_registry import WlRegistryProxy +from pywayland.protocol.wayland.wl_surface import WlSurface + + +@dataclass +class GlobalRegistry: + surface: WlSurface | None = None + inhibit_manager: ZwpIdleInhibitManagerV1 | None = None + + +def handle_registry_global( + wl_registry: WlRegistryProxy, id_num: int, iface_name: str, version: int +) -> None: + global_registry: GlobalRegistry = wl_registry.user_data or GlobalRegistry() + + if iface_name == "wl_compositor": + compositor = wl_registry.bind(id_num, WlCompositor, version) + global_registry.surface = compositor.create_surface() # type: ignore + elif iface_name == "zwp_idle_inhibit_manager_v1": + global_registry.inhibit_manager = wl_registry.bind( + id_num, ZwpIdleInhibitManagerV1, version + ) + + +def main() -> None: + done = Event() + signal(SIGINT, lambda _, __: done.set()) + signal(SIGTERM, lambda _, __: done.set()) + + global_registry = GlobalRegistry() + + display = Display() + display.connect() + + registry = display.get_registry() # type: ignore + registry.user_data = global_registry + registry.dispatcher["global"] = handle_registry_global + + def shutdown() -> None: + display.dispatch() + display.roundtrip() + display.disconnect() + + display.dispatch() + display.roundtrip() + + if global_registry.surface is None or global_registry.inhibit_manager is None: + print("Wayland seems not to support idle_inhibit_unstable_v1 protocol.") + shutdown() + sys.exit(1) + + inhibitor = global_registry.inhibit_manager.create_inhibitor( # type: ignore + global_registry.surface + ) + + display.dispatch() + display.roundtrip() + + print("Inhibiting idle...") + done.wait() + print("Shutting down...") + + inhibitor.destroy() + + shutdown() + + +if __name__ == "__main__": + setproctitle.setproctitle("wayland-idle-inhibitor.py") + main()