diff --git a/Bar.qml b/Bar.qml deleted file mode 100644 index 0837f5a..0000000 --- a/Bar.qml +++ /dev/null @@ -1,38 +0,0 @@ -pragma ComponentBehavior: Bound -import QtQuick -import QtQuick.Layouts -import Quickshell - -PanelWindow { - id: root - color: "transparent" - - anchors { - top: true - bottom: true - left: true - } - width: 60 - - ColumnLayout { - // anchors.fill: parent - anchors.margins: 2 - spacing: 2 - anchors { - left: parent.left - right: parent.right - top: parent.top - margins: 2 - } - - ClockWidget {} - - WorkspaceWidget { - bar: root - wsBaseIndex: root.screen.name == "DP-2" ? 11 : 1 - } - SysTray { - bar: root - } - } -} diff --git a/ClockWidget.qml b/ClockWidget.qml index 2e58c2e..6cf0ad7 100644 --- a/ClockWidget.qml +++ b/ClockWidget.qml @@ -1,18 +1,26 @@ import QtQuick -import QtQuick.Layouts import Quickshell Rectangle { - width: parent.width - height: text.height + 10 - border.color: "black" + + + width: text.width + implicitHeight: text.height + // border.color: "black" border.width: 2 - radius: 5 - color: "#30c0ffff" + radius: 0 + color: "transparent" + + Behavior on implicitHeight { + NumberAnimation { + duration: 100 + easing.type: Easing.OutCubic + } + } Item { width: parent.width - height: text.height * 2 + height: text.height anchors.centerIn: parent @@ -26,11 +34,11 @@ Rectangle { anchors.centerIn: parent property var date: Date() - text: Qt.formatDateTime(clock.date, "hh\nmm") + text: Qt.formatDateTime(clock.date, "hh mm") font.family: "ComicShannsMono Nerd Font Mono" font.weight: Font.ExtraBold - font.pointSize: 18 + font.pointSize: 12 color: "black" } diff --git a/Launcher.qml b/Launcher.qml index 30dacdb..183175e 100644 --- a/Launcher.qml +++ b/Launcher.qml @@ -7,6 +7,8 @@ import Quickshell.Io import Quickshell.Wayland import Quickshell.Widgets +import "./config" + Singleton { id: launcher property bool launcherOpen: false @@ -32,11 +34,10 @@ Singleton { activeAsync: launcher.launcherOpen PanelWindow { - width: 450 - height: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10 + implicitWidth: 450 + implicitHeight: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10 color: "transparent" WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive - WlrLayershell.namespace: "shell:launcher" Rectangle { @@ -48,9 +49,9 @@ Singleton { } } width: 450 - color: "#30c0afaf" + color: Config.catppuccin.base radius: 5 - border.color: "black" + border.color: Config.catppuccin.mantle border.width: 2 ColumnLayout { @@ -63,24 +64,20 @@ Singleton { id: searchContainer Layout.fillWidth: true implicitHeight: searchbox.implicitHeight + 10 - color: "#30c0ffff" + color: Config.catppuccin.base radius: 3 - border.color: "#50ffffff" + border.color: Config.catppuccin.mantle RowLayout { id: searchbox anchors.fill: parent anchors.margins: 5 - IconImage { - implicitSize: parent.height - source: "root:icons/magnifying-glass.svg" - } - TextInput { id: search Layout.fillWidth: true - color: "black" + color: Config.catppuccin.text + font.pointSize: 13 focus: true Keys.forwardTo: [list] @@ -254,9 +251,9 @@ Singleton { highlight: Rectangle { radius: 5 - color: "#20e0ffff" - border.color: "#30ffffff" - border.width: 1 + color: "transparent" + border.color: Config.catppuccin.lavender + border.width: 2 } keyNavigationEnabled: true keyNavigationWraps: true @@ -296,8 +293,9 @@ Singleton { } Text { text: modelData.name - color: "black" - font.family: "ComicShannsMono Nerd Font Mono" + color: Config.catppuccin.text + font.family: "JetBrainsMono Nerd Font Mono" + font.pointSize: 13 Layout.alignment: Qt.AlignVCenter } } diff --git a/SysTray.qml b/SysTray.qml index 3fe54c5..7445bcd 100644 --- a/SysTray.qml +++ b/SysTray.qml @@ -18,7 +18,7 @@ Rectangle { border.color: "black" border.width: 2 - ColumnLayout { + RowLayout { id: column spacing: 10 diff --git a/WorkspaceWidget.qml b/WorkspaceWidget.qml deleted file mode 100644 index e2ceecf..0000000 --- a/WorkspaceWidget.qml +++ /dev/null @@ -1,116 +0,0 @@ -// A workspace indicator. -// This is in big parts taken from outfoxxed, the creator of quickshell. -// Please make sure to check out his setup. -pragma ComponentBehavior: Bound -import QtQuick -import Quickshell.Hyprland - -Rectangle { - id: root - required property var bar - - readonly property HyprlandMonitor monitor: Hyprland.monitorFor(bar.screen) - - // Amount of workspaces - property int wsCount: 10 - // Base index for the workspaces - property int wsBaseIndex: 1 - - // index of the current workspace - property int currentIndex: 0 - // count how many workspaces currently exist - property int existsCount: 0 - - implicitHeight: column.implicitHeight + 10 - - width: parent.width - height: width - border.color: "black" - color: "#30c0ffff" - border.width: 2 - radius: 5 - - // destructor takes care of nulling - signal workspaceAdded(workspace: HyprlandWorkspace) - - Column { - id: column - spacing: 0 - anchors { - fill: parent - margins: 5 - } - - Repeater { - model: root.wsCount - - Item { - id: wsItem - implicitHeight: 15 - - anchors { - right: parent.right - left: parent.left - } - - // index of the current workspace - required property int index - property int wsIndex: root.wsBaseIndex + index - - property HyprlandWorkspace workspace: null - // check if workspace exists - property bool exists: workspace != null - - property bool active: (root.monitor?.activeWorkspace ?? false) && root.monitor.activeWorkspace == workspace - - Connections { - target: root - - function onWorkspaceAdded(workspace: HyprlandWorkspace) { - if (workspace.id == wsItem.wsIndex) { - wsItem.workspace = workspace; - } - } - } - - property real animActive: active ? 1 : 0.65 - Behavior on animActive { - NumberAnimation { - duration: 150 - } - } - - property real animExists: exists ? 1 : 0 - Behavior on animExists { - NumberAnimation { - duration: 100 - } - } - - Rectangle { - anchors.centerIn: parent - height: wsItem.height - 5 - width: parent.width * wsItem.animActive - radius: height / 2 - border.color: "black" - border.width: 1 - color: "black" - } - } - } - } - - Connections { - target: Hyprland.workspaces - - function onObjectInsertedPost(workspace) { - root.workspaceAdded(workspace); - } - } - - Component.onCompleted: { - Hyprland.workspaces.values.forEach(workspace => { - root.workspaceAdded(workspace); - }); - } -} diff --git a/config/Config.qml b/config/Config.qml new file mode 100644 index 0000000..875a4df --- /dev/null +++ b/config/Config.qml @@ -0,0 +1,46 @@ +pragma Singleton + +import Quickshell +import QtQuick + +Singleton { + id: root + + readonly property QtObject bar: QtObject { + readonly property int width: 50 + readonly property var colors: QtObject { + readonly property color bar: "#1e1e2e" + readonly property color barOutline: "#50ffffff" + readonly property color widget: "#25ceffff" + readonly property color widgetActive: "#80ceffff" + readonly property color widgetOutline: "#40ffffff" + readonly property color widgetOutlineSeparate: "#20ffffff" + readonly property color separator: "#60ffffff" + } + } + + readonly property QtObject border: QtObject { + readonly property int thickness: 8 + readonly property color color: "#1e1e2e" + readonly property int rounding: 25 + } + + readonly property QtObject catppuccin: QtObject { + readonly property color base: "#1e1e2e" + readonly property color mantle: "#181825" + readonly property color surface0: "#313244" + readonly property color surface1: "#45475a" + readonly property color surface2: "#585b70" + readonly property color text: "#cdd6f4" + readonly property color rosewater: "#f5e0dc" + readonly property color lavender: "#b4befe" + readonly property color red: "#f38ba8" + readonly property color peach: "#fab387" + readonly property color yellow: "#f9e2af" + readonly property color green: "#a6e3a1" + readonly property color teal: "#a6e3a1" + readonly property color blue: "#89b4fa" + readonly property color mauve: "#cba6f7" + readonly property color flamingo: "#f2cdcd" + } +} diff --git a/crashes/cysjzw2dys/info.txt b/crashes/cysjzw2dys/info.txt new file mode 100644 index 0000000..c79ee65 --- /dev/null +++ b/crashes/cysjzw2dys/info.txt @@ -0,0 +1,85 @@ +===== Build Information ===== +Git Revision: 95d0af8113394b1fdb71c94ac5160c83b8b829cb +Buildtime Qt Version: 6.9.0 +Build Type: RelWithDebInfo +Compiler: Clang (19.1.7) +Complie Flags: + +Build configuration: + Distributor: Official-Nix-Flake + Distributor provided debuginfo: TRUE + Disable precompild headers (dev): OFF + Build tests (dev): OFF + ASAN (dev): OFF + Keep Frame Pointers (dev): OFF + Crash Handling: TRUE + Use jemalloc: TRUE + Unix Sockets: ON + Wayland: TRUE + Wlroots Layer-Shell: ON + Session Lock: ON + Foreign Toplevel Management: ON + Hyprland: TRUE + Hyprland IPC: ON + Hyprland Global Shortcuts: ON + Hyprland Focus Grabbing: ON + Hyprland Surface Extensions: ON + Screencopy: TRUE + Image Copy Capture: ON + Wlroots Screencopy: ON + Hyprland Toplevel Export: ON + X11: ON + I3/Sway: TRUE + I3/Sway IPC: ON + System Tray: ON + PipeWire: TRUE + Mpris: ON + Pam: TRUE + Greetd: ON + UPower: ON + Notifications: ON + +===== Runtime Information ===== +Runtime Qt Version: 6.9.0 +Crashed process ID: 934130 +Run ID: cysjzw2dys +Shell ID: 3d5bdcfe44ead3996569d85a1bee5ccd +Config Path: /home/cr/.config/quickshell/shell.qml + +===== Report Integrity ===== +Minidump save status: 0 +Log save status: 0 +Binary copy status: 0 + +===== System Information ===== + +/etc/os-release: +ANSI_COLOR="0;38;2;126;186;228" +BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues" +BUILD_ID="25.11.20250617.9e83b64" +CPE_NAME="cpe:/o:nixos:nixos:25.11" +DEFAULT_HOSTNAME=nixos +DOCUMENTATION_URL="https://nixos.org/learn.html" +HOME_URL="https://nixos.org/" +ID=nixos +ID_LIKE="" +IMAGE_ID="" +IMAGE_VERSION="" +LOGO="nix-snowflake" +NAME=NixOS +PRETTY_NAME="NixOS 25.11 (Xantusia)" +SUPPORT_URL="https://nixos.org/community.html" +VARIANT="" +VARIANT_ID="" +VENDOR_NAME=NixOS +VENDOR_URL="https://nixos.org/" +VERSION="25.11 (Xantusia)" +VERSION_CODENAME=xantusia +VERSION_ID="25.11" + +/etc/lsb-release: +DISTRIB_CODENAME=xantusia +DISTRIB_DESCRIPTION="NixOS 25.11 (Xantusia)" +DISTRIB_ID=nixos +DISTRIB_RELEASE="25.11" +LSB_VERSION="25.11 (Xantusia)" diff --git a/crashes/cysjzw2dys/krash b/crashes/cysjzw2dys/krash new file mode 100644 index 0000000..2dbafd3 --- /dev/null +++ b/crashes/cysjzw2dys/krash @@ -0,0 +1,141 @@ + PID: 934130 (.quickshell-wra) + UID: 1000 (cr) + GID: 100 (users) + Signal: 11 (SEGV) + Timestamp: Tue 2025-06-24 17:05:45 CEST (1min 6s ago) + Command Line: /nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/quickshell + Executable: /nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + Control Group: /user.slice/user-1000.slice/user@1000.service/app.slice/app-ghostty-transient-893450.scope/surfaces/56064E44FCE0.scope + Unit: user@1000.service + User Unit: app-ghostty-transient-893450.scope + Slice: user-1000.slice + Owner UID: 1000 (cr) + Boot ID: cf8c340fb08a42959615d04c1ed95e43 + Machine ID: 34366a1d940e471481fb5b10aa9acce4 + Hostname: hermit + Storage: /var/lib/systemd/coredump/core.\x2equickshell-wra.1000.cf8c340fb08a42959615d04c1ed95e43.934130.1750777545000000.zst (present) + Size on Disk: 7.8M + Message: Process 934130 (.quickshell-wra) of user 1000 dumped core. + + Module libwebpmux.so.3 without build-id. + Module libwebpdemux.so.2 without build-id. + Module libwebp.so.7 without build-id. + Module libLerc.so.4 without build-id. + Module libdeflate.so.0 without build-id. + Module libtiff.so.6 without build-id. + Module liblcms2.so.2 without build-id. + Module libmng.so.2 without build-id. + Module libatomic.so.1 without build-id. + Module libvmaf.so.3 without build-id. + Module libnuma.so.1 without build-id. + Module libsharpyuv.so.0 without build-id. + Module libaom.so.3 without build-id. + Module libde265.so without build-id. + Module libx265.so.215 without build-id. + Module libheif.so.1 without build-id. + Module libjasper.so.7 without build-id. + Module libjpeg.so.62 without build-id. + Module libpciaccess.so.0 without build-id. + Module liblzma.so.5 without build-id. + Module libxml2.so.2 without build-id. + Module libdrm_intel.so.1 without build-id. + Module libdrm_amdgpu.so.1 without build-id. + Module libxshmfence.so.1 without build-id. + Module libxcb-sync.so.1 without build-id. + Module libsensors.so.5 without build-id. + Module libxcb-present.so.0 without build-id. + Module libxcb-dri3.so.0 without build-id. + Module libxcb-shm.so.0 without build-id. + Module libxcb-xfixes.so.0 without build-id. + Module libxcb-randr.so.0 without build-id. + Module libX11-xcb.so.1 without build-id. + Module libunistring.so.5 without build-id. + Module libselinux.so.1 without build-id. + Module libpsl.so.5 without build-id. + Module libssh2.so.1 without build-id. + Module libidn2.so.0 without build-id. + Module libnghttp2.so.14 without build-id. + Module libduktape.so.207 without build-id. + Module libgomp.so.1 without build-id. + Module libcap.so.2 without build-id. + Module libpxbackend-1.0.so without build-id. + Module libbrotlicommon.so.1 without build-id. + Module libkeyutils.so.1 without build-id. + Module libkrb5support.so.0 without build-id. + Module libcom_err.so.3 without build-id. + Module libk5crypto.so.3 without build-id. + Module libkrb5.so.3 without build-id. + Module libgraphite2.so.3 without build-id. + Module libpcre2-8.so.0 without build-id. + Module libexpat.so.1 without build-id. + Module libbz2.so.1 without build-id. + Module libpcre2-16.so.0 without build-id. + Module libb2.so.1 without build-id. + Module libdouble-conversion.so.3 without build-id. + Module libicudata.so.76 without build-id. + Module libicuuc.so.76 without build-id. + Module libicui18n.so.76 without build-id. + Module libproxy.so.1 without build-id. + Module libzstd.so.1 without build-id. + Module libbrotlidec.so.1 without build-id. + Module libgssapi_krb5.so.2 without build-id. + Module libXext.so.6 without build-id. + Module libz.so.1 without build-id. + Module libfreetype.so.6 without build-id. + Module libmd4c.so.0 without build-id. + Module libharfbuzz.so.0 without build-id. + Module libpng16.so.16 without build-id. + Module libX11.so.6 without build-id. + Module libfontconfig.so.1 without build-id. + Module libvulkan.so without build-id. + Module libaudit.so.1 without build-id. + Module libXdmcp.so.6 without build-id. + Module libXau.so.6 without build-id. + Module libffi.so.8 without build-id. + Module libGLdispatch.so.0 without build-id. + Module libgcc_s.so.1 without build-id. + Module libstdc++.so.6 without build-id. + Module libOpenGL.so.0 without build-id. + Module libGLX.so.0 without build-id. + Module libpam.so.0 without build-id. + Module libpipewire-0.3.so.0 without build-id. + Module libxcb.so.1 without build-id. + Module libxkbcommon.so.0 without build-id. + Module libEGL.so.1 without build-id. + Module libgbm.so.1 without build-id. + Module libdrm.so.2 without build-id. + Module libjemalloc.so.2 without build-id. + Stack trace of thread 934130: + #0 0x000055b31f19466b _ZN14PostReloadHook14postReloadTreeEP7QObject (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x12566b) + #1 0x000055b31f194699 _ZN14PostReloadHook14postReloadTreeEP7QObject (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x125699) + #2 0x000055b31f194699 _ZN14PostReloadHook14postReloadTreeEP7QObject (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x125699) + #3 0x000055b31f19fe76 _ZN9QtPrivate15QCallableObjectIZN16EngineGeneration8onReloadEPS1_E3$_0NS_4ListIJEEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x130e76) + #4 0x00007f0dc001c7a0 _Z10doActivateILb0EEvP7QObjectiPPv (libQt6Core.so.6 + 0x21c7a0) + #5 0x00007f0dc00129a3 _ZN7QObject9destroyedEPS_ (libQt6Core.so.6 + 0x2129a3) + #6 0x00007f0dc0018f8b _ZN7QObjectD1Ev (libQt6Core.so.6 + 0x218f8b) + #7 0x000055b31f19cf45 _ZN16EngineGenerationD1Ev (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x12df45) + #8 0x000055b31f19cfb9 _ZN16EngineGenerationD0Ev (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x12dfb9) + #9 0x000055b31f19fe08 _ZN9QtPrivate15QCallableObjectIZN16EngineGeneration7destroyEvE3$_0NS_4ListIJEEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x130e08) + #10 0x00007f0dc001c7a0 _Z10doActivateILb0EEvP7QObjectiPPv (libQt6Core.so.6 + 0x21c7a0) + #11 0x00007f0dc00129a3 _ZN7QObject9destroyedEPS_ (libQt6Core.so.6 + 0x2129a3) + #12 0x00007f0dc0018f8b _ZN7QObjectD1Ev (libQt6Core.so.6 + 0x218f8b) + #13 0x000055b31f1ed6c9 _ZN11QQmlPrivate11QQmlElementI9ShellRootED0Ev (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x17e6c9) + #14 0x00007f0dc000dc86 _ZN7QObject5eventEP6QEvent (libQt6Core.so.6 + 0x20dc86) + #15 0x00007f0dbffb2698 _ZN16QCoreApplication15notifyInternal2EP7QObjectP6QEvent (libQt6Core.so.6 + 0x1b2698) + #16 0x00007f0dbffb63e4 _ZN23QCoreApplicationPrivate16sendPostedEventsEP7QObjectiP11QThreadData (libQt6Core.so.6 + 0x1b63e4) + #17 0x00007f0dc02c42c7 _ZL23postEventSourceDispatchP8_GSourcePFiPvES1_ (libQt6Core.so.6 + 0x4c42c7) + #18 0x00007f0dbf90181e g_main_context_dispatch_unlocked (libglib-2.0.so.0 + 0x6181e) + #19 0x00007f0dbf903a90 g_main_context_iterate_unlocked.isra.0 (libglib-2.0.so.0 + 0x63a90) + #20 0x00007f0dbf9042bc g_main_context_iteration (libglib-2.0.so.0 + 0x642bc) + #21 0x00007f0dc02c39a3 _ZN20QEventDispatcherGlib13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE (libQt6Core.so.6 + 0x4c39a3) + #22 0x00007f0dbffc0beb _ZN10QEventLoop4execE6QFlagsINS_17ProcessEventsFlagEE (libQt6Core.so.6 + 0x1c0beb) + #23 0x00007f0dbffbc02e _ZN16QCoreApplication4execEv (libQt6Core.so.6 + 0x1bc02e) + #24 0x000055b31f11b062 _ZN2qs6launch6launchERKNS0_10LaunchArgsEPPcP16QCoreApplication (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0xac062) + #25 0x000055b31f1126f0 _ZN2qs6launch12_GLOBAL__N_117launchFromCommandERNS0_12CommandStateEP16QCoreApplication (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0xa36f0) + #26 0x000055b31f111a63 _ZN2qs6launch10runCommandEiPPcP16QCoreApplication (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0xa2a63) + #27 0x000055b31f108999 _ZN2qs6launch4mainEiPPc (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x99999) + #28 0x00007f0dbf62a47e __libc_start_call_main (libc.so.6 + 0x2a47e) + #29 0x00007f0dbf62a539 __libc_start_main@@GLIBC_2.34 (libc.so.6 + 0x2a539) + #30 0x000055b31f106b25 _start (/nix/store/yv42brzi79h6q6sfawxynh6wdmbm1jwc-quickshell-0.1.0/bin/.quickshell-wrapped + 0x97b25) + ELF object binary architecture: AMD x86-64 + diff --git a/crashes/cysjzw2dys/log.qslog.log b/crashes/cysjzw2dys/log.qslog.log new file mode 100644 index 0000000..d74c952 Binary files /dev/null and b/crashes/cysjzw2dys/log.qslog.log differ diff --git a/modules/bar/Bar.qml b/modules/bar/Bar.qml new file mode 100644 index 0000000..b0fc519 --- /dev/null +++ b/modules/bar/Bar.qml @@ -0,0 +1,50 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Quickshell + +import "../../config" +import "components" + +Item { + id: root + + required property ShellScreen screen + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + } + + implicitWidth: Config.bar.width + + Item { + id: child + + anchors { + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + + implicitWidth: Math.max(clock.implicitWidth, workspaces.implicitWidth) + + ColumnLayout { + spacing: 2 + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: 0 + } + Clock { + id: clock + } + Workspaces { + id: workspaces + screen: root.screen + } + } + } +} diff --git a/modules/bar/components/Clock.qml b/modules/bar/components/Clock.qml new file mode 100644 index 0000000..4826851 --- /dev/null +++ b/modules/bar/components/Clock.qml @@ -0,0 +1,34 @@ +import QtQuick +import Quickshell + +import "../../../config" + +Rectangle { + id: root + + width: text.width + 5 + height: text.height + 5 + implicitWidth: width + border.color: Config.catppuccin.rosewater + border.width: 0 + radius: 5 + color: "transparent" + + Text { + id: text + anchors.centerIn: parent + property var date: Date() + + text: Qt.formatDateTime(clock.date, "hh mm") + + font.family: "JetBrainsMono NF Mono" + font.pointSize: 15 + + color: Config.catppuccin.text + } + + SystemClock { + id: clock + precision: SystemClock.Seconds + } +} diff --git a/modules/bar/components/Workspaces.qml b/modules/bar/components/Workspaces.qml new file mode 100644 index 0000000..91bc9d2 --- /dev/null +++ b/modules/bar/components/Workspaces.qml @@ -0,0 +1,109 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import QtQuick.Layouts + +import "../../../services/niri" +import "../../../config" + +Rectangle { + id: root + + required property ShellScreen screen + property var workspaces: Niri.workspaces + property var wsCount: Niri.workspaces.length + property var activeWorkspace: Niri.activeWorkspace + property var activeWorkspaceIndex: Niri.activeWorkspaceIndex + + property int wsItemHeight: 15 + + signal workspaceAdded(workspace: var) + function onWorkspaceAdded(workspace: var) { + root.workspaces.push(workspace); + } + + // property bool _: log() + // function log() { + // console.log(workspaces.values); + // return true; + // } + + // Works + height: 300 + + // Gives warning + // height: workspaces.length * root.wsItemHeight + implicitWidth: list.implicitWidth + color: "transparent" + border.color: Config.catppuccin.rosewater + border.width: 0 + radius: 7 + + Layout.fillWidth: true + + ListView { + id: list + model: root.workspaces + implicitHeight: contentHeight + implicitWidth: contentItem.childrenRect.width + anchors.horizontalCenter: parent.horizontalCenter + + // anchors.fill: parent + + delegate: Item { + id: wsItem + // Name of the workspace + property string name: "VOID" + // ID of the workspace + required property string id + + required property string output + + property bool isActive: (id - 1 == root.activeWorkspaceIndex) + + property real animActive: isActive ? 1 : 0.65 + Behavior on animActive { + NumberAnimation { + duration: 150 + } + } + + // property bool isCorrectScreen: log() + // function log() { + // console.log("Screen name: " + root.screen.name); + // console.log(wsItem.output); + // console.log(wsItem.id); + + // let isCorrect = root.screen.name == wsItem.output; + // console.log("isCorrect: ", isCorrect); + // return root.screen.name == wsItem.output; + // } + + implicitHeight: root.wsItemHeight + implicitWidth: 50 + + anchors { + right: parent.right + left: parent.left + } + + Rectangle { + anchors.centerIn: parent + height: wsItem.height - 5 + width: parent.width * wsItem.animActive + radius: height / 2 + border.color: Config.catppuccin.mantle + border.width: 0 + color: Config.catppuccin.blue + } + } + } + + Component.onCompleted: { + Niri.workspaces.forEach(workspace => { + root.workspaceAdded(workspace); + }); + } +} diff --git a/modules/drawers/Backgrounds.qml b/modules/drawers/Backgrounds.qml new file mode 100644 index 0000000..388efc4 --- /dev/null +++ b/modules/drawers/Backgrounds.qml @@ -0,0 +1,9 @@ +import Quickshell +import QtQuick +import QtQuick.Shapes + +import "../notifications" as Notifications + +Rectangle { + required property Item bar +} diff --git a/modules/drawers/Border.qml b/modules/drawers/Border.qml new file mode 100644 index 0000000..9117fee --- /dev/null +++ b/modules/drawers/Border.qml @@ -0,0 +1,54 @@ +import Quickshell +import QtQuick +import QtQuick.Effects + +import "../../config" + +Item { + id: root + + required property Item bar + + anchors.fill: parent + + Rectangle { + id: rect + + anchors.fill: parent + color: Config.border.color + visible: false + + + Behavior on color { + ColorAnimation { + duration: 150 + easing.type: Easing.BezierSpline + } + } + } + + Item { + id: mask + + anchors.fill: parent + layer.enabled: true + visible: false + + Rectangle { + anchors.fill: parent + anchors.margins: Config.border.thickness + anchors.leftMargin: root.bar.implicitWidth + radius: Config.border.rounding + } + } + + MultiEffect { + anchors.fill: parent + maskEnabled: true + maskInverted: true + maskSource: mask + source: rect + maskThresholdMin: 0.5 + maskSpreadAtMin: 1 + } +} diff --git a/modules/drawers/Drawers.qml b/modules/drawers/Drawers.qml new file mode 100644 index 0000000..eb85dea --- /dev/null +++ b/modules/drawers/Drawers.qml @@ -0,0 +1,105 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Wayland +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Effects + +import "../bar" +import "../volume" +import "../notifications" + +import "../../services" +import "../../config" + +Variants { + model: Quickshell.screens + + Scope { + id: scope + required property ShellScreen modelData + + Exclusions { + screen: scope.modelData + bar: bar + } + + PanelWindow { + id: win + + screen: scope.modelData + color: "transparent" + + WlrLayershell.exclusionMode: ExclusionMode.Ignore + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + + // Clickthrough mask. + // Clickable areas of the window are determined by the provided region. + mask: Region { + // Start at the bottom left; right of the bar and on top of the border + x: bar.implicitWidth + y: Config.border.thickness + + // Width is the window width - the bar's width - the border thickness + width: win.width - bar.implicitWidth - Config.border.thickness + + // Height is window width - the border thickness x2 —top border and bottom border. + height: win.height - Config.border.thickness * 2 + + // Setting the intersection mode to Xor will invert the mask and make everything in the mask region not clickable and pass through clicks inside it through the window. + intersection: Intersection.Xor + Region { + item: volume + intersection: Intersection.Subtract + } + } + + anchors { + top: true + bottom: true + left: true + right: true + } + + Item { + id: background + + anchors.fill: parent + visible: false + + Border { + bar: bar + } + + Backgrounds { + bar: bar + } + } + + MultiEffect { + anchors.fill: source + source: background + shadowEnabled: true + blurMax: 15 + } + + Bar { + id: bar + screen: scope.modelData + } + + VolumeSlider { + id: volume + isInRightPanel: hover.isInRightPanel + screen: scope.modelData + } + + Hover { + id: hover + screen: scope.modelData + bar: bar + } + } + } +} diff --git a/modules/drawers/Exclusions.qml b/modules/drawers/Exclusions.qml new file mode 100644 index 0000000..d99092d --- /dev/null +++ b/modules/drawers/Exclusions.qml @@ -0,0 +1,38 @@ + +pragma ComponentBehavior: Bound +import Quickshell +import QtQuick + +import "../../config" + +Scope { + id: root + required property ShellScreen screen + required property Item bar + + ExclusionZone { + anchors.left: true + exclusiveZone: root.bar.implicitWidth + } + + ExclusionZone { + anchors.top: true + } + + ExclusionZone { + anchors.right: true + } + + ExclusionZone { + anchors.bottom: true + } + + component ExclusionZone: PanelWindow { + screen: root.screen + color: "transparent" + exclusiveZone: Config.border.thickness + implicitHeight: Config.border.thickness + implicitWidth: Config.border.thickness + mask: Region {} + } +} diff --git a/modules/launcher/Launcher.qml b/modules/launcher/Launcher.qml new file mode 100644 index 0000000..8cf4f37 --- /dev/null +++ b/modules/launcher/Launcher.qml @@ -0,0 +1,319 @@ +pragma Singleton +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Layouts +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Widgets + +Singleton { + id: launcher + property bool launcherOpen: false + + IpcHandler { + target: "launcher" + + function open(): void { + launcher.launcherOpen = true; + } + + function close(): void { + launcher.launcherOpen = false; + } + + function toggle(): void { + launcher.launcherOpen = !launcher.launcherOpen; + } + } + + LazyLoader { + id: loader + activeAsync: launcher.launcherOpen + + PanelWindow { + width: 450 + height: 7 + searchContainer.implicitHeight + list.topMargin * 2 + list.delegateHeight * 10 + color: "transparent" + + + anchors { + bottom: parent.bottom + } + + + WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive + WlrLayershell.namespace: "shell:launcher" + + Rectangle { + + height: 7 + searchContainer.implicitHeight + list.topMargin + list.bottomMargin + Math.min(list.contentHeight, list.delegateHeight * 10) + Behavior on height { + NumberAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + width: 450 + color: "#30c0afaf" + radius: 5 + border.color: "black" + border.width: 2 + + ColumnLayout { + anchors.fill: parent + anchors.margins: 7 + anchors.bottomMargin: 0 + spacing: 0 + + Rectangle { + id: searchContainer + Layout.fillWidth: true + implicitHeight: searchbox.implicitHeight + 10 + color: "#30c0ffff" + radius: 3 + border.color: "#50ffffff" + + RowLayout { + id: searchbox + anchors.fill: parent + anchors.margins: 5 + + IconImage { + implicitSize: parent.height + source: "root:icons/magnifying-glass.svg" + } + + TextInput { + id: search + Layout.fillWidth: true + color: "black" + + focus: true + Keys.forwardTo: [list] + Keys.onEscapePressed: launcher.launcherOpen = false + + Keys.onPressed: event => { + if (event.modifiers & Qt.ControlModifier) { + if (event.key == Qt.Key_J) { + list.currentIndex = list.currentIndex == list.count - 1 ? 0 : list.currentIndex + 1; + event.accepted = true; + } else if (event.key == Qt.Key_K) { + list.currentIndex = list.currentIndex == 0 ? list.count - 1 : list.currentIndex - 1; + event.accepted = true; + } + } + } + + onAccepted: { + if (list.currentItem) { + list.currentItem.clicked(null); + } + } + + onTextChanged: { + list.currentIndex = 0; + } + } + } + } + + ListView { + id: list + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + cacheBuffer: 0 // works around QTBUG-131106 + //reuseItems: true + model: ScriptModel { + values: DesktopEntries.applications.values.map(object => { + const stxt = search.text.toLowerCase(); + const ntxt = object.name.toLowerCase(); + let si = 0; + let ni = 0; + + let matches = []; + let startMatch = -1; + + for (let si = 0; si != stxt.length; ++si) { + const sc = stxt[si]; + + while (true) { + // Drop any entries with letters that don't exist in order + if (ni == ntxt.length) + return null; + + const nc = ntxt[ni++]; + + if (nc == sc) { + if (startMatch == -1) + startMatch = ni; + break; + } else { + if (startMatch != -1) { + matches.push({ + index: startMatch, + length: ni - startMatch + }); + + startMatch = -1; + } + } + } + } + + if (startMatch != -1) { + matches.push({ + index: startMatch, + length: ni - startMatch + 1 + }); + } + + return { + object: object, + matches: matches + }; + }).filter(entry => entry !== null).sort((a, b) => { + let ai = 0; + let bi = 0; + let s = 0; + + while (ai != a.matches.length && bi != b.matches.length) { + const am = a.matches[ai]; + const bm = b.matches[bi]; + + s = bm.length - am.length; + if (s != 0) + return s; + + s = am.index - bm.index; + if (s != 0) + return s; + + ++ai; + ++bi; + } + + s = a.matches.length - b.matches.length; + if (s != 0) + return s; + + s = a.object.name.length - b.object.name.length; + if (s != 0) + return s; + + return a.object.name.localeCompare(b.object.name); + }).map(entry => entry.object) + + onValuesChanged: list.currentIndex = 0 + } + + topMargin: 7 + bottomMargin: list.count == 0 ? 0 : 7 + + add: Transition { + NumberAnimation { + property: "opacity" + from: 0 + to: 1 + duration: 100 + } + } + + displaced: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + move: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 1 + duration: 100 + } + } + + remove: Transition { + NumberAnimation { + property: "y" + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + property: "opacity" + to: 0 + duration: 100 + } + } + + highlight: Rectangle { + radius: 5 + color: "#20e0ffff" + border.color: "#30ffffff" + border.width: 1 + } + keyNavigationEnabled: true + keyNavigationWraps: true + highlightMoveVelocity: -1 + highlightMoveDuration: 50 + preferredHighlightBegin: list.topMargin + preferredHighlightEnd: list.height - list.bottomMargin + highlightRangeMode: ListView.ApplyRange + snapMode: ListView.SnapToItem + + readonly property real delegateHeight: 44 + + delegate: MouseArea { + required property DesktopEntry modelData + + implicitHeight: list.delegateHeight + implicitWidth: ListView.view.width + + onClicked: { + modelData.execute(); + launcher.launcherOpen = false; + } + + RowLayout { + id: delegateLayout + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: 5 + } + + IconImage { + Layout.alignment: Qt.AlignVCenter + asynchronous: true + implicitSize: 30 + source: Quickshell.iconPath(modelData.icon) + } + Text { + text: modelData.name + color: "black" + font.family: "ComicShannsMono Nerd Font Mono" + Layout.alignment: Qt.AlignVCenter + } + } + } + } + } + } + } + } + function init() { + } +} diff --git a/modules/notifications/Notification.qml b/modules/notifications/Notification.qml new file mode 100644 index 0000000..2569210 --- /dev/null +++ b/modules/notifications/Notification.qml @@ -0,0 +1,18 @@ +import Quickshell +import Quickshell.Widgets +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Layouts + +import "../../config" +import "../../services" + +Rectangle { + id: root + color: "transparent" + required property Notification.Notif modelData + + Text { + text: root.modelData.summary + } +} diff --git a/modules/volume/VolumeSlider.qml b/modules/volume/VolumeSlider.qml new file mode 100644 index 0000000..af00a16 --- /dev/null +++ b/modules/volume/VolumeSlider.qml @@ -0,0 +1,41 @@ +pragma ComponentBehavior: Bound + +import Quickshell +import Quickshell.Wayland +import Quickshell.Services.Notifications +import QtQuick +import QtQuick.Effects + +Rectangle { + id: root + required property bool isInRightPanel + required property ShellScreen screen + property bool isVisible + color: "transparent" + + property bool _: log() + function log() { + console.log(hover.hovered); + return true + } + + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + } + + implicitWidth: 60 + implicitHeight: screen.height / 3 + + HoverHandler { + id: hover + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad + } + + Rectangle { + anchors.right: parent.right + color: "green" + implicitWidth: hover.hovered | root.isInRightPanel ? 60 : 10 + implicitHeight: root.screen.height / 3 + } +} diff --git a/qmlcache/2269da1129b1cc2d04ba8f904947ed9ce9e43a79.qmlc b/qmlcache/2269da1129b1cc2d04ba8f904947ed9ce9e43a79.qmlc new file mode 100644 index 0000000..28eab7d Binary files /dev/null and b/qmlcache/2269da1129b1cc2d04ba8f904947ed9ce9e43a79.qmlc differ diff --git a/services/Hover.qml b/services/Hover.qml new file mode 100644 index 0000000..cd29894 --- /dev/null +++ b/services/Hover.qml @@ -0,0 +1,49 @@ +import Quickshell +import QtQuick +import "../config" + +MouseArea { + id: root + + anchors.fill: parent + hoverEnabled: true + + required property ShellScreen screen + // required property Panels panels + required property Item bar + + property bool showVolumeMenu: false + property bool isInRightPanel: false + + // function withinPanelHeight(panel: Item, x: real, y: real): bool { + // const panelY = Config.border.thickness + panel.y; + // return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding; + // } + + // function inLeftBorder(x: real, y: real): bool { + // return x <= Config.border.thickness; + // } + + function inRightPanel(x: real, y: real): bool { + // Cursor is in middle veritcal third of screen + // Cursor is in the right border + return y >= root.screen.height / 3 && y <= (root.screen.height / 3) * 2 && x >= root.screen.width - Config.border.thickness; + } + + // Update on mouse cursor movement + onPositionChanged: event => { + const x = event.x; + const y = event.y; + + root.isInRightPanel = inRightPanel(x, y); + + console.log("In right panel: " + root.isInRightPanel); + + console.log("x:" + x + " y: " + y); + } + onContainsMouseChanged: { + if (!containsMouse) { + root.isInRightPanel = false; + } + } +} diff --git a/services/Notification.qml b/services/Notification.qml new file mode 100644 index 0000000..bdf52de --- /dev/null +++ b/services/Notification.qml @@ -0,0 +1,20 @@ +pragma Singleton +pragma ComponentBehavior: Bound + +import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Services.Notifications + +/** + * Provides extra features not in Quickshell.Services.Notifications: + * - Persistent storage + * - Popup notifications, with timeout + * - Notification groups by app + */ +Singleton { + id: root + NotificationServer { + + } +} diff --git a/services/niri/Niri.qml b/services/niri/Niri.qml new file mode 100644 index 0000000..de16157 --- /dev/null +++ b/services/niri/Niri.qml @@ -0,0 +1,94 @@ +// Kind thanks to https://github.com/MapoMagpie/nixos-flakes/blob/main/home/ui/quickshell/config/Data/Niri.qml +// This file was taken from there and further modified. + +pragma Singleton + +import QtQuick +import Quickshell +import Quickshell.Io + +Singleton { + id: root + // property var data + property var workspaces: [] + property var activeWorkspace: "VOID" + property var activeWorkspaceIndex: 0 + property var windows: [] + // property var activedWindowId: 0 + + Process { + id: proc + command: ["niri", "msg", "-j", "event-stream"] + + running: true + stdout: SplitParser { + onRead: data => { + var event = JSON.parse(data); + let workspaces = []; + if (event.WorkspacesChanged) { + root.workspaces = event.WorkspacesChanged.workspaces; + root.workspaces = root.workspaces.sort((a, b) => a.id - b.id); + root.activeWorkspaceIndex = root.workspaces.findIndex(w => w.is_focused); + if (root.activeWorkspaceIndex < 0) { + root.activeWorkspaceIndex = 0; + } + root.activeWorkspace = root.workspaces[root.activeWorkspaceIndex].name; + } + if (event.WindowsChanged) { + root.windows = [...event.WindowsChanged.windows].sort((a, b) => a.id - b.id); + } + if (event.WindowOpenedOrChanged) { + const window = event.WindowOpenedOrChanged.window; + const index = root.windows.findIndex(w => w.id === window.id); + // console.log("window opened or changed: ", index, ", win id: ", window.id); + if (index >= 0) { + // console.log("replace window, old: ", root.windows[index].id, ", new: ", window.id); + root.windows[index] = window; + } else { + // console.log("push window, new: ", window.id); + root.windows.push(window); + } + root.windows = [...root.windows.sort((a, b) => a.id - b.id)]; + } + if (event.WindowClosed) { + const index = root.windows.findIndex(w => w.id === event.WindowClosed.id); + // console.log("window closed: ", index, ", win id: ", event.WindowClosed.id); + if (index >= 0) { + root.windows.splice(index, 1); + } + root.windows = [...root.windows.sort((a, b) => a.id - b.id)]; + } + if (event.WorkspaceActivated) { + root.activeWorkspaceIndex = root.workspaces.findIndex(w => w.id === event.WorkspaceActivated.id); + if (root.activeWorkspaceIndex < 0) { + root.activeWorkspaceIndex = 0; + } + root.activeWorkspace = root.workspaces[root.activeWorkspaceIndex].name; + } + } + } + } + // component Workspace: QtObject { + // required property int id + // property int idx + // property string name: "VOID" + // required property string output + // property bool is_active + // property bool is_focused + // property int active_window_id + // } +} + +// { +// "workspaces": [ +// { +// "id": 5, +// "idx": 4, +// "name": "GAME", +// "output": "DP-3", +// "is_active": false, +// "is_focused": false, +// "active_window_id": null +// }, +// ] +// } diff --git a/shell.qml b/shell.qml index 4f7231f..05fea55 100644 --- a/shell.qml +++ b/shell.qml @@ -1,24 +1,21 @@ -pragma ComponentBehavior: Bound +//@ pragma Env QS_NO_RELOAD_POPUP=1 import Quickshell import QtQuick +import "modules" +import "modules/drawers" +import "services" + +// import "modules/background" + ShellRoot { id: shellroot Component.onCompleted: [Launcher.init()] - ReloadPopup {} + Drawers {} + // Background {}Popup + // - Variants { - model: Quickshell.screens - - Scope { - property var modelData - - Bar { - screen: modelData - } - } - } }