From b214993c161b995cc214d320bd8dc5cf51ae1c43 Mon Sep 17 00:00:00 2001 From: eren <98850034+EisregenHaha@users.noreply.github.com> Date: Fri, 28 Nov 2025 12:51:19 +0100 Subject: [PATCH 01/16] Add Qalculate as Dependency for Fedora fixes math --- sdata/dist-fedora/feddeps.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdata/dist-fedora/feddeps.toml b/sdata/dist-fedora/feddeps.toml index f21169a1b..2a1bf2df5 100644 --- a/sdata/dist-fedora/feddeps.toml +++ b/sdata/dist-fedora/feddeps.toml @@ -181,6 +181,7 @@ packages = [ "hyprpicker", "songrec", "translate-shell", + "qalculate", "wlogout" ] @@ -191,4 +192,4 @@ packages = [ "plasma-systemmonitor", "unzip" ] -install_opts = ["--setopt=install_weak_deps=False"] \ No newline at end of file +install_opts = ["--setopt=install_weak_deps=False"] From 04f73e67c8eee60ccf1fdf553e46c246c6948c01 Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 28 Nov 2025 21:07:39 +0800 Subject: [PATCH 02/16] Add qalc dep for dist-arch and deps-info (#2591) --- sdata/deps-info.md | 3 +++ sdata/dist-arch/illogical-impulse-widgets/PKGBUILD | 3 ++- sdata/dist-fedora/feddeps.toml | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/sdata/deps-info.md b/sdata/deps-info.md index fc6f315a3..9a1e4e826 100644 --- a/sdata/deps-info.md +++ b/sdata/deps-info.md @@ -191,6 +191,9 @@ Tips: - Used in Quickshell config. - `wlogout` - Used in Hyprland config. +- `libqalculate` + - Used in Quickshell config, providing math ability in searchbar. + - Note that `qalc` is the needed executable. In Arch Linux [libqalculate](https://archlinux.org/packages/extra/x86_64/libqalculate) provides it, but in Fedora [qalculate](https://packages.fedoraproject.org/pkgs/libqalculate/qalculate/fedora-43.html#files) does and [libqalculate](https://packages.fedoraproject.org/pkgs/libqalculate/libqalculate/fedora-43.html#files) does not. # Actual packages diff --git a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD index 76f71d43f..fa9d4df02 100644 --- a/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD +++ b/sdata/dist-arch/illogical-impulse-widgets/PKGBUILD @@ -1,6 +1,6 @@ pkgname=illogical-impulse-widgets pkgver=1.0 -pkgrel=5 +pkgrel=6 pkgdesc='Illogical Impulse Widget Dependencies' arch=(any) license=(None) @@ -14,4 +14,5 @@ depends=( songrec translate-shell wlogout + libqalculate ) diff --git a/sdata/dist-fedora/feddeps.toml b/sdata/dist-fedora/feddeps.toml index 2a1bf2df5..367626ced 100644 --- a/sdata/dist-fedora/feddeps.toml +++ b/sdata/dist-fedora/feddeps.toml @@ -193,3 +193,4 @@ packages = [ "unzip" ] install_opts = ["--setopt=install_weak_deps=False"] + From b4038dafa900509e4784eb0980aa7e78878d06f4 Mon Sep 17 00:00:00 2001 From: clsty Date: Fri, 28 Nov 2025 22:42:47 +0800 Subject: [PATCH 03/16] Update dist-nix - Not use NixGL but let home-manager automatically handle it (since hm 25.11) - Add libqalculate --- sdata/dist-nix/README.md | 34 ++++++++++++++++++++-- sdata/dist-nix/home-manager/flake.nix | 19 +++++++----- sdata/dist-nix/home-manager/home.nix | 19 ++++++++---- sdata/dist-nix/home-manager/quickshell.nix | 10 +++++-- sdata/dist-nix/install-deps.sh | 5 ++-- 5 files changed, 67 insertions(+), 20 deletions(-) diff --git a/sdata/dist-nix/README.md b/sdata/dist-nix/README.md index 3a8120e04..9aca1d13f 100644 --- a/sdata/dist-nix/README.md +++ b/sdata/dist-nix/README.md @@ -37,8 +37,38 @@ As [commented](https://github.com/end-4/dots-hyprland/issues/1061#issuecomment-3 See also [caelestia-dots/shell#668](https://github.com/caelestia-dots/shell/issues/668). -### NixGL -On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. `nixGL` should be used to address the problem. +### GPU +On non-NixOS distros, packages installed via home-manager have problem accessing GPU, especially Hyprland because it requires GPU acceleration to launch. + +~~`nixGL` should be used to address the problem.~~ + +Since home-manager 25.11, for non-NixOS just set the following: +```nix +targets.genericLinux.enable = true; +``` +Then during building, home-manager will show a message to tell you running a command manually to configure GPU, like: +```bash +sudo /nix/store/-non-nixos-gpu/bin/non-nixos-gpu-setup +``` +It runs a bash script with following content: +``` +#!/nix/store/-bash-/bin/bash + +set -e + +# Install the systemd service file and ensure that the store path won't be +# garbage-collected as long as it's installed. +unit_path=/etc/systemd/system/non-nixos-gpu.service +ln -sf /nix/store/-non-nixos-gpu/resources/non-nixos-gpu.service "$unit_path" +ln -sf "$unit_path" "/nix/var/nix"/gcroots/non-nixos-gpu.service + +systemctl daemon-reload +systemctl enable non-nixos-gpu.service +systemctl restart non-nixos-gpu.service +``` +_Note: it uses `systemctl`, maybe won't work for OpenRC..._ + +See [gpu-non-nixos](https://nix-community.github.io/home-manager/index.xhtml#sec-usage-gpu-non-nixos). # Handling dot files ## Status diff --git a/sdata/dist-nix/home-manager/flake.nix b/sdata/dist-nix/home-manager/flake.nix index d88daad6e..97a50c466 100644 --- a/sdata/dist-nix/home-manager/flake.nix +++ b/sdata/dist-nix/home-manager/flake.nix @@ -3,23 +3,24 @@ description = "illogical-impulse"; inputs = { - # Qt 6.10 is not yet available from released version of nixpkgs. - #nixpkgs.url = "nixpkgs/nixos-25.05"; - nixpkgs.url = "nixpkgs/nixos-unstable"; + nixpkgs.url = "nixpkgs/nixos-25.11"; + #nixpkgs.url = "nixpkgs/nixos-unstable"; home-manager = { - #url = "github:nix-community/home-manager/release-25.05"; - url = "github:nix-community/home-manager/master"; + url = "github:nix-community/home-manager/release-25.11"; + #url = "github:nix-community/home-manager/master"; inputs.nixpkgs.follows = "nixpkgs"; }; - nixgl.url = "github:nix-community/nixGL"; + #nixgl.url = "github:nix-community/nixGL"; quickshell = { url = "github:quickshell-mirror/quickshell/db1777c20b936a86528c1095cbcb1ebd92801402"; inputs.nixpkgs.follows = "nixpkgs"; }; }; - outputs = { nixpkgs, home-manager, nixgl, quickshell, ... }: + outputs = { nixpkgs, home-manager, + #nixgl, + quickshell, ... }: let home_attrs = rec { username = import ./username.nix; @@ -36,7 +37,9 @@ homeConfigurations = { illogical_impulse = home-manager.lib.homeManagerConfiguration { inherit pkgs; - extraSpecialArgs = { inherit home_attrs nixgl quickshell; }; + extraSpecialArgs = { inherit home_attrs + #nixgl + quickshell; }; modules = [ ./home.nix ]; diff --git a/sdata/dist-nix/home-manager/home.nix b/sdata/dist-nix/home-manager/home.nix index 596430395..b1381481d 100644 --- a/sdata/dist-nix/home-manager/home.nix +++ b/sdata/dist-nix/home-manager/home.nix @@ -1,8 +1,13 @@ -{ config, lib, pkgs, nixgl, quickshell, home_attrs, ... }: +{ config, lib, pkgs, +#nixgl, +quickshell, home_attrs, ... }: { programs.home-manager.enable = true; - nixGL.packages = nixgl.packages; - nixGL.defaultWrapper = "mesa"; + + # Necessary for non-NixOS to handle GPU (since home-manager version 25.11) + targets.genericLinux.enable = true; + #nixGL.packages = nixgl.packages; + #nixGL.defaultWrapper = "mesa"; xdg.portal = { enable = true; @@ -27,7 +32,8 @@ systemd.enable = false; plugins = []; settings = {}; extraConfig = ""; enable = true; ## Use NixGL - package = config.lib.nixGL.wrap pkgs.hyprland; + #package = config.lib.nixGL.wrap pkgs.hyprland; + package = pkgs.hyprland; }; home = { @@ -167,6 +173,7 @@ songrec #songrec translate-shell #translate-shell wlogout #wlogout + libqalculate #libqalculate ] ++ [ @@ -174,7 +181,9 @@ ### illogical-impulse-quickshell-git #(config.lib.nixGL.wrap quickshell.packages.x86_64-linux.default) - (import ./quickshell.nix { inherit pkgs quickshell; nixGLWrap = config.lib.nixGL.wrap; }) + (import ./quickshell.nix { inherit pkgs quickshell; + #nixGLWrap = config.lib.nixGL.wrap; + }) ]; }//home_attrs; } diff --git a/sdata/dist-nix/home-manager/quickshell.nix b/sdata/dist-nix/home-manager/quickshell.nix index 0fb7b57fe..fb81af848 100644 --- a/sdata/dist-nix/home-manager/quickshell.nix +++ b/sdata/dist-nix/home-manager/quickshell.nix @@ -1,10 +1,14 @@ -{ pkgs, quickshell, nixGLWrap, ... }: +{ pkgs, quickshell, +#nixGLWrap, +... }: let - qs = nixGLWrap quickshell.packages.x86_64-linux.default; + #qs = nixGLWrap quickshell.packages.x86_64-linux.default; + qs = quickshell.packages.x86_64-linux.default; in pkgs.stdenv.mkDerivation { name = "illogical-impulse-quickshell-wrapper"; meta = with pkgs.lib; { - description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage"; + #description = "Quickshell wrapped with NixGL + bundled Qt deps for home-manager usage"; + description = "Quickshell bundled Qt deps for home-manager usage"; license = licenses.gpl3Only; }; diff --git a/sdata/dist-nix/install-deps.sh b/sdata/dist-nix/install-deps.sh index 357bb498f..2049efb82 100644 --- a/sdata/dist-nix/install-deps.sh +++ b/sdata/dist-nix/install-deps.sh @@ -32,8 +32,8 @@ function install_home-manager(){ try source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh command -v $cmd && return - x nix-channel --add https://nixos.org/channels/nixos-25.05 nixpkgs-home - x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.05.tar.gz home-manager + x nix-channel --add https://nixos.org/channels/nixos-25.11 nixpkgs-home + x nix-channel --add https://github.com/nix-community/home-manager/archive/release-25.11.tar.gz home-manager x nix-channel --update x env NIX_PATH="nixpkgs=$HOME/.nix-defexpr/channels/nixpkgs-home" nix-shell '' -A install @@ -56,6 +56,7 @@ function hm_deps(){ x home-manager switch --flake .#illogical_impulse \ --extra-experimental-features nix-command \ --extra-experimental-features flakes + x sudo /nix/store/*-non-nixos-gpu/bin/non-nixos-gpu-setup cd $REPO_ROOT x git rm -f "${SETUP_USERNAME_NIXFILE}" } From 6b90e37b0f16678bd90858e3339b03161996849a Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 29 Nov 2025 00:23:19 +0100 Subject: [PATCH 04/16] waffles: expandable notifs --- .../ii/modules/waffle/bar/BarButton.qml | 29 +---- .../ii/modules/waffle/looks/AcrylicButton.qml | 42 +++++++ .../modules/waffle/looks/AcrylicRectangle.qml | 9 +- .../ii/modules/waffle/looks/Looks.qml | 3 + .../ii/modules/waffle/looks/WText.qml | 3 + .../NotificationHeaderButton.qml | 18 ++- .../SmallBorderedIconAndTextButton.qml | 11 +- .../notificationCenter/WNotificationGroup.qml | 14 ++- .../WSingleNotification.qml | 106 ++++++++++++++++-- 9 files changed, 185 insertions(+), 50 deletions(-) create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml index 53a37cba0..4502b22f7 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml @@ -5,17 +5,12 @@ import qs.modules.common import qs.modules.common.functions import qs.modules.waffle.looks -WButton { +AcrylicButton { id: root property var altAction: () => {} property var middleClickAction: () => {} - colBackground: ColorUtils.transparentize(Looks.colors.bg1) - colBackgroundHover: Looks.colors.bg1Hover - colBackgroundActive: Looks.colors.bg1Active - property color colBackgroundBorder - property color color Layout.fillHeight: true topInset: 4 bottomInset: 4 @@ -23,16 +18,7 @@ WButton { rightInset: 0 horizontalPadding: 8 - colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, (root.checked || root.hovered) ? Looks.backgroundTransparency : 1) - color: { - if (root.down) { - return root.colBackgroundActive - } else if ((root.hovered && !root.down) || root.checked) { - return root.colBackgroundHover - } else { - return root.colBackground - } - } + colBackground: ColorUtils.transparentize(Looks.colors.bg1) MouseArea { anchors.fill: parent @@ -50,15 +36,4 @@ WButton { } } - background: AcrylicRectangle { - shiny: ((root.hovered && !root.down) || root.checked) - color: root.color - radius: Looks.radius.medium - border.width: 1 - border.color: root.colBackgroundBorder - - Behavior on border.color { - animation: Looks.transition.color.createObject(this) - } - } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml new file mode 100644 index 000000000..ef5c0747a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicButton.qml @@ -0,0 +1,42 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +WButton { + id: root + + colBackground: Looks.colors.bg1 + colBackgroundHover: Looks.colors.bg1Hover + colBackgroundActive: Looks.colors.bg1Active + property color colBackgroundBorder + property color color + property alias border: background.border + property alias shinyColor: background.borderColor + + colBackgroundBorder: ColorUtils.transparentize(color, (root.checked || root.hovered) ? Looks.backgroundTransparency : 0) + color: { + if (root.down) { + return root.colBackgroundActive + } else if ((root.hovered && !root.down) || root.checked) { + return root.colBackgroundHover + } else { + return root.colBackground + } + } + + background: AcrylicRectangle { + id: background + shiny: ((root.hovered && !root.down) || root.checked) + color: root.color + radius: Looks.radius.medium + border.width: 1 + border.color: root.colBackgroundBorder + + Behavior on border.color { + animation: Looks.transition.color.createObject(this) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml index 7e041d111..7fecaa068 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml @@ -9,16 +9,17 @@ Rectangle { id: root property bool shiny: true // Top border - property color borderColor: ColorUtils.transparentize(Looks.colors.bg2Border, shiny ? 0.5 : 1) + property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Hover, 0.7) + property color internalBorderColor: ColorUtils.transparentize(borderColor, shiny ? 0.0 : 1) color: Looks.colors.bg1Hover radius: Looks.radius.medium Behavior on color { animation: Looks.transition.color.createObject(this) } - Behavior on borderColor { + Behavior on internalBorderColor { animation: Looks.transition.color.createObject(this) } - onBorderColorChanged: { + onInternalBorderColorChanged: { borderCanvas.requestPaint(); } @@ -32,7 +33,7 @@ Rectangle { var ctx = getContext("2d"); ctx.clearRect(0, 0, width, height); - var borderColor = root.borderColor; + var borderColor = root.internalBorderColor; var r = root.radius; var fadeLength = Math.max(1, r); diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml index e55f840cb..a321fa98e 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml @@ -53,6 +53,7 @@ Singleton { property color controlBgHover: '#57575B' property color controlFg: "#FFFFFF" property color accentUnfocused: "#848484" + property color link: "#235CCF" } darkColors: QtObject { id: darkColors @@ -80,6 +81,7 @@ Singleton { property color controlBgHover: "#CFCED1" property color controlFg: "#454545" property color accentUnfocused: "#989898" + property color link: "#A7C9FC" } colors: QtObject { id: colors @@ -110,6 +112,7 @@ Singleton { property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg + property color link: root.dark ? root.darkColors.link : root.lightColors.link property color danger: "#C42B1C" property color dangerActive: "#B62D1F" property color warning: "#FF9900" diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml index 240fd63be..0da156893 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml @@ -8,8 +8,11 @@ Text { color: Looks.colors.fg font { + hintingPreference: Font.PreferFullHinting family: Looks.font.family.ui pixelSize: Looks.font.pixelSize.normal weight: Looks.font.weight.regular } + + linkColor: Looks.colors.link } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml index 860451fc3..9aa20a690 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationHeaderButton.qml @@ -8,18 +8,24 @@ import qs.modules.common.functions import qs.modules.waffle.looks WBorderlessButton { - id: headerButton + id: root Layout.fillWidth: false - implicitWidth: 16 - implicitHeight: 16 + property real implicitSize: 16 + implicitWidth: implicitSize + implicitHeight: implicitSize color: "transparent" + colForeground: root.hovered && !root.pressed ? Looks.colors.fg : Looks.colors.fg1 + + Behavior on colForeground { + animation: Looks.transition.color.createObject(this) + } contentItem: Item { FluentIcon { anchors.centerIn: parent - implicitSize: 16 - icon: headerButton.icon.name - color: headerButton.hovered && !headerButton.pressed ? Looks.colors.fg : Looks.colors.fg1 + implicitSize: root.implicitSize + icon: root.icon.name + color: root.colForeground } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml index c4331a7dc..faab4d90d 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/SmallBorderedIconAndTextButton.qml @@ -2,18 +2,27 @@ import QtQuick import qs import qs.services import qs.modules.common +import qs.modules.common.functions import qs.modules.waffle.looks -SmallBorderedIconButton { +AcrylicButton { id: root property bool iconVisible: true property string iconName: "" property bool iconFilled: true + colBackground: Looks.colors.bg2 + colBackgroundHover: Looks.colors.bg2Hover + colBackgroundActive: Looks.colors.bg2Active + property color colBorder: Looks.colors.bg2Border + property color colBorderToggled: Looks.colors.accent + border.color: checked ? colBorderToggled : colBorder + leftPadding: 12 rightPadding: 12 implicitWidth: focusButtonContent.implicitWidth + leftPadding + rightPadding + implicitHeight: 24 contentItem: Row { id: focusButtonContent diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml index 837c7c016..21ef2c544 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml @@ -12,6 +12,7 @@ MouseArea { required property var notificationGroup readonly property var notifications: notificationGroup?.notifications ?? [] + property bool expanded: false implicitWidth: contentLayout.implicitWidth implicitHeight: contentLayout.implicitHeight @@ -34,12 +35,23 @@ MouseArea { interactive: false spacing: 4 model: ScriptModel { - values: root.notifications.slice().reverse() + values: root.expanded ? root.notifications.slice().reverse() : root.notifications.slice(-1) + objectProp: "notificationId" } delegate: WSingleNotification { + required property int index required property var modelData width: ListView.view.width notification: modelData + groupExpandControlMessage: { + if (root.notifications.length === 0) return ""; + if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1); + if (index === root.notifications.length - 1) return Translation.tr("See fewer"); + return ""; + } + onGroupExpandToggle: { + root.expanded = !root.expanded; + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml index 42a832adb..95780133c 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml @@ -13,10 +13,17 @@ MouseArea { required property var notification property bool expanded: false + property string groupExpandControlMessage: "" + signal groupExpandToggle + hoverEnabled: true implicitHeight: contentItem.implicitHeight implicitWidth: contentItem.implicitWidth + Behavior on implicitHeight { + animation: Looks.transition.enter.createObject(this) + } + Rectangle { id: contentItem anchors.fill: parent @@ -26,32 +33,109 @@ MouseArea { implicitHeight: notificationContent.implicitHeight + padding * 2 implicitWidth: notificationContent.implicitWidth + padding * 2 border.width: 1 - border.color: Looks.applyContentTransparency(Looks.colors.ambientShadow) + border.color: ColorUtils.applyAlpha(Looks.colors.ambientShadow, 0.1) ColumnLayout { id: notificationContent anchors.fill: parent anchors.margins: contentItem.padding + spacing: 19 RowLayout { Layout.fillWidth: true - WText { - text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time) + + ExpandButton { + Layout.topMargin: -2 + } + + Item { + Layout.fillWidth: true + } + + NotificationHeaderButton { + Layout.rightMargin: 4 + opacity: root.containsMouse ? 1 : 0 + icon.name: "dismiss" + implicitSize: 12 + onClicked: { + Qt.callLater(() => { + Notifications.discardNotification(root.notification?.notificationId); + }); + } } } ColumnLayout { Layout.fillWidth: true - WText { - Layout.fillWidth: true - elide: Text.ElideRight - text: root.notification.summary + spacing: 3 + + SummaryText {} + BodyText {} + } + + AcrylicButton { + id: groupExpandButton + visible: root.groupExpandControlMessage !== "" + Layout.bottomMargin: 2 + horizontalPadding: 10 + implicitHeight: 24 + implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2 + onClicked: root.groupExpandToggle() + contentItem: Item { + WText { + id: expandButtonText + anchors.centerIn: parent + text: root.groupExpandControlMessage + } } + } + } + } + + component SummaryText: WText { + Layout.fillWidth: true + elide: Text.ElideRight + text: root.notification?.summary + font.pixelSize: Looks.font.pixelSize.large + } + + component BodyText: WText { + Layout.fillWidth: true + Layout.fillHeight: true + elide: Text.ElideRight + verticalAlignment: Text.AlignTop + wrapMode: Text.Wrap + maximumLineCount: root.expanded ? 100 : 1 + text: root.notification?.body + color: Looks.colors.subfg + } + + component ExpandButton: NotificationHeaderButton { + id: expandButton + implicitWidth: expandButtonContent.implicitWidth + onClicked: root.expanded = !root.expanded + + contentItem: Item { + id: expandButtonContent + implicitWidth: expandButtonRow.implicitWidth + implicitHeight: expandButtonRow.implicitHeight + RowLayout { + id: expandButtonRow + anchors.centerIn: parent + spacing: 8 WText { - Layout.fillWidth: true - elide: Text.ElideRight - wrapMode: Text.Wrap - maximumLineCount: root.expanded ? 100 : 1 + color: expandButton.colForeground + text: NotificationUtils.getFriendlyNotifTimeString(root.notification?.time) + } + FluentIcon { + Layout.rightMargin: 12 + icon: "chevron-down" + implicitSize: 18 + rotation: root.expanded ? -180 : 0 + color: expandButton.colForeground + Behavior on rotation { + animation: Looks.transition.rotate.createObject(this) + } } } } From d2c019f8de66e1cbd268878e626c4d1f3a237241 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 29 Nov 2025 00:37:15 +0100 Subject: [PATCH 05/16] fix "+0 notifications" --- .../ii/modules/waffle/notificationCenter/WNotificationGroup.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml index 21ef2c544..122469771 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml @@ -44,7 +44,7 @@ MouseArea { width: ListView.view.width notification: modelData groupExpandControlMessage: { - if (root.notifications.length === 0) return ""; + if (root.notifications.length <= 1) return ""; if (!root.expanded) return Translation.tr("+%1 notifications").arg(root.notifications.length - 1); if (index === root.notifications.length - 1) return Translation.tr("See fewer"); return ""; From 3cf14671ad5ffcb984c1e176e5839b2ca885f8fe Mon Sep 17 00:00:00 2001 From: vaguesyntax Date: Sat, 29 Nov 2025 02:40:28 +0300 Subject: [PATCH 06/16] fix: get gif size properly --- .../modules/common/utils/ImageDownloaderProcess.qml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml b/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml index 11ff92a6d..3a86b2fe1 100644 --- a/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml +++ b/dots/.config/quickshell/ii/modules/common/utils/ImageDownloaderProcess.qml @@ -18,14 +18,19 @@ Process { running: true command: ["bash", "-c", - `mkdir -p $(dirname '${processFilePath(filePath)}'); [ -f '${processFilePath(filePath)}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath(filePath)}' && magick identify -format '%w %h' '${processFilePath(filePath)}'[0]` + `mkdir -p $(dirname '${processFilePath()}'); [ -f '${processFilePath()}' ] || curl -sSL '${sourceUrl}' -o '${processFilePath()}' && file '${processFilePath()}'` ] stdout: StdioCollector { id: imageSizeOutputCollector onStreamFinished: { const output = imageSizeOutputCollector.text.trim(); - const [width, height] = output.split(" ").map(Number); - root.done(root.filePath, width, height); + const match = output.match(/(\d+)\s*x\s*(\d+)/); + + if (match) { + const width = Number(match[1]); + const height = Number(match[2]); + root.done(root.filePath, width, height); + } } } } From 677fa06b06934174109e00206b2661ed2d686468 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 29 Nov 2025 12:51:31 +0100 Subject: [PATCH 07/16] waffles: notifications: image support --- .../common/functions/NotificationUtils.qml | 24 +++ .../common/widgets/NotificationItem.qml | 31 +--- .../ii/modules/waffle/bar/StartButton.qml | 1 + .../NotificationCenterContent.qml | 19 ++- .../WSingleNotification.qml | 157 ++++++++++++++---- 5 files changed, 172 insertions(+), 60 deletions(-) diff --git a/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml index 8a336e8ad..d6adcc0f6 100644 --- a/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml +++ b/dots/.config/quickshell/ii/modules/common/functions/NotificationUtils.qml @@ -84,4 +84,28 @@ Singleton { // Older dates return Qt.formatDateTime(messageTime, "MMMM dd"); } + + function processNotificationBody(body, appName) { + let processedBody = body + + // Clean Chromium-based browsers notifications - remove first line + if (appName) { + const lowerApp = appName.toLowerCase() + const chromiumBrowsers = [ + "brave", "chrome", "chromium", "vivaldi", "opera", "microsoft edge" + ] + + if (chromiumBrowsers.some(name => lowerApp.includes(name))) { + const lines = body.split('\n\n') + + if (lines.length > 1 && lines[0].startsWith(' lowerApp.includes(name))) { - const lines = body.split('\n\n') - - if (lines.length > 1 && lines[0].startsWith('") + return NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
") } } } ColumnLayout { // Expanded content + id: expandedContentColumn Layout.fillWidth: true opacity: root.expanded ? 1 : 0 visible: opacity > 0 @@ -218,8 +197,8 @@ Item { // Notification item area elide: Text.ElideRight textFormat: Text.RichText text: { - return `` + - `${processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
")}` + return `` + + `${NotificationUtils.processNotificationBody(notificationObject.body, notificationObject.appName || notificationObject.summary).replace(/\n/g, "
")}` } onLinkActivated: (link) => { @@ -293,6 +272,8 @@ Item { // Notification item area id: actionRepeater model: notificationObject.actions NotificationActionButton { + id: notifAction + required property var modelData Layout.fillWidth: true buttonText: modelData.text urgency: notificationObject.urgency diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml index f4a15cc00..5ec96eeb4 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml @@ -7,6 +7,7 @@ import qs.services import qs.modules.common import qs.modules.waffle.looks +// TODO: Replace the icon with QMLized svg (with /usr/lib/qt6/bin/svgtoqml) for proper micro-animation AppButton { id: root diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml index 797cee28a..47ad2f92d 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml @@ -20,6 +20,7 @@ WBarAttachedPanelContent { property bool collapsed: false contentItem: ColumnLayout { + id: contentLayout anchors { horizontalCenter: parent.horizontalCenter top: parent.top @@ -41,9 +42,24 @@ WBarAttachedPanelContent { } contentItem: NotificationPaneContent { implicitWidth: calendarColumnLayout.implicitWidth - implicitHeight: Notifications.list.length > 0 ? (notificationArea.height - notificationPane.borderWidth * 2) : 230 + implicitHeight: { + if (Notifications.list.length > 0) { + return ((contentLayout.height - calendarPane.height - contentLayout.spacing) - notificationPane.borderWidth * 2) + } + return 230; + } + Timer { + id: enableTimer + interval: Config.options.hacks.arbitraryRaceConditionDelay + onTriggered: heightBehavior.enabled = true; + } Behavior on implicitHeight { + id: heightBehavior + enabled: false + Component.onCompleted: { + enableTimer.restart(); + } animation: Looks.transition.enter.createObject(this) } } @@ -51,6 +67,7 @@ WBarAttachedPanelContent { } WPane { + id: calendarPane contentItem: ColumnLayout { id: calendarColumnLayout spacing: 0 diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml index 95780133c..856ddb160 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Layouts import Quickshell @@ -41,52 +42,115 @@ MouseArea { anchors.margins: contentItem.padding spacing: 19 - RowLayout { + // Header + SingleNotificationHeader { Layout.fillWidth: true + } - ExpandButton { - Layout.topMargin: -2 + // Content + Item { + id: actualContent + Layout.fillWidth: true + Layout.fillHeight: true + property real spacing: 16 + implicitHeight: Math.max(contentColumn.implicitHeight, imageLoader.height) + implicitWidth: contentColumn.implicitWidth + + Loader { + id: imageLoader + active: root.notification.image != "" + sourceComponent: StyledImage { + width: 48 + height: 48 + sourceSize.width: width + sourceSize.height: height + source: root.notification.image + } } - Item { - Layout.fillWidth: true - } + ColumnLayout { + id: contentColumn + anchors { + top: parent.top + left: parent.left + right: parent.right + } + spacing: 3 - NotificationHeaderButton { - Layout.rightMargin: 4 - opacity: root.containsMouse ? 1 : 0 - icon.name: "dismiss" - implicitSize: 12 - onClicked: { - Qt.callLater(() => { - Notifications.discardNotification(root.notification?.notificationId); - }); + SummaryText { + id: summaryText + Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0 + } + BodyText { + Layout.leftMargin: imageLoader.active ? imageLoader.width + actualContent.spacing : 0 + // onLineLaidOut: (line) => { + // if (!imageLoader.active) return; + // const dodgeDistance = imageLoader.width + actualContent.spacing; + // // print(line.y, dodgeDistance) + // if (summaryText.height + line.y > dodgeDistance) { + // line.x -= dodgeDistance; + // line.width += dodgeDistance; + // } + // } } } } - ColumnLayout { + // Actions + ActionsRow { Layout.fillWidth: true - spacing: 3 - - SummaryText {} - BodyText {} } - AcrylicButton { - id: groupExpandButton - visible: root.groupExpandControlMessage !== "" + // "+1 notifications" button + GroupExpandButton { Layout.bottomMargin: 2 - horizontalPadding: 10 - implicitHeight: 24 - implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2 - onClicked: root.groupExpandToggle() - contentItem: Item { - WText { - id: expandButtonText - anchors.centerIn: parent - text: root.groupExpandControlMessage - } + } + } + } + + component SingleNotificationHeader: RowLayout { + ExpandButton { + Layout.topMargin: -2 + } + + Item { + Layout.fillWidth: true + } + + NotificationHeaderButton { + Layout.rightMargin: 4 + opacity: root.containsMouse ? 1 : 0 + icon.name: "dismiss" + implicitSize: 12 + onClicked: { + Qt.callLater(() => { + Notifications.discardNotification(root.notification?.notificationId); + }); + } + } + } + + component ActionsRow: RowLayout { + visible: root.expanded && root.notification.actions.length > 0 + uniformCellSizes: true + Repeater { + id: actionRepeater + model: root.notification.actions + delegate: WBorderedButton { + id: actionButton + Layout.fillHeight: true + required property var modelData + Layout.fillWidth: true + verticalPadding: 16 + horizontalPadding: 12 + text: modelData.text + implicitHeight: actionButtonText.implicitHeight + verticalPadding * 2 + contentItem: WText { + id: actionButtonText + text: actionButton.text + font.pixelSize: Looks.font.pixelSize.large + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.Wrap } } } @@ -106,8 +170,17 @@ MouseArea { verticalAlignment: Text.AlignTop wrapMode: Text.Wrap maximumLineCount: root.expanded ? 100 : 1 - text: root.notification?.body + text: { + if (root.expanded) + return `` + `${NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "
")}`; + return NotificationUtils.processNotificationBody(root.notification.body, root.notification.appName || root.notification.summary).replace(/\n/g, "
"); + } color: Looks.colors.subfg + textFormat: root.expanded ? Text.RichText : Text.StyledText + onLinkActivated: link => { + Qt.openUrlExternally(link); + GlobalStates.sidebarRightOpen = false; + } } component ExpandButton: NotificationHeaderButton { @@ -140,4 +213,20 @@ MouseArea { } } } + + component GroupExpandButton: AcrylicButton { + id: groupExpandButton + visible: root.groupExpandControlMessage !== "" + horizontalPadding: 10 + implicitHeight: 24 + implicitWidth: expandButtonText.implicitWidth + horizontalPadding * 2 + onClicked: root.groupExpandToggle() + contentItem: Item { + WText { + id: expandButtonText + anchors.centerIn: parent + text: root.groupExpandControlMessage + } + } + } } From 44422004791e8d651bf3094bfb6d51e7f1dee737 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Sat, 29 Nov 2025 23:23:58 +0100 Subject: [PATCH 08/16] waffles: start menu base --- dots/.config/hypr/hyprland/keybinds.conf | 32 ++--- dots/.config/quickshell/ii/GlobalStates.qml | 1 + .../ii/assets/icons/fluent/power-filled.svg | 4 + .../ii/assets/icons/fluent/power.svg | 4 + .../fluent/system-search-checked-dark.svg | 14 +-- .../fluent/system-search-checked-light.svg | 16 +-- .../ii/modules/common/Directories.qml | 4 + .../ii/modules/common/widgets/StyledImage.qml | 10 ++ .../modules/common/widgets/StyledToolTip.qml | 1 + .../ii/modules/ii/overview/Overview.qml | 22 ++-- .../ii/modules/waffle/bar/AppButton.qml | 2 +- .../ii/modules/waffle/bar/StartButton.qml | 3 +- .../ii/modules/waffle/bar/WidgetsButton.qml | 2 +- .../waffle/bar/tasks/WindowPreview.qml | 2 +- .../ii/modules/waffle/looks/Looks.qml | 6 +- .../{bar/AppIcon.qml => looks/WAppIcon.qml} | 1 - .../ii/modules/waffle/looks/WButton.qml | 3 +- .../ii/modules/waffle/looks/WTextInput.qml | 18 +++ .../NotificationCenterContent.qml | 3 +- .../WSingleNotification.qml | 16 ++- .../ii/modules/waffle/startMenu/SearchBar.qml | 84 +++++++++++++ .../waffle/startMenu/SearchPageContent.qml | 16 +++ .../waffle/startMenu/StartMenuContent.qml | 39 ++++++ .../waffle/startMenu/StartPageContent.qml | 98 +++++++++++++++ .../waffle/startMenu/WaffleStartMenu.qml | 119 ++++++++++++++++++ dots/.config/quickshell/ii/shell.qml | 5 +- 26 files changed, 464 insertions(+), 61 deletions(-) create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/power.svg rename dots/.config/quickshell/ii/modules/waffle/{bar/AppIcon.qml => looks/WAppIcon.qml} (94%) create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index 020fe582d..6032ab65a 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -4,27 +4,27 @@ #! ##! Shell # These absolutely need to be on top, or they won't work consistently -bindid = Super, Super_L, Toggle overview, global, quickshell:overviewToggleRelease # Toggle overview/launcher -bindid = Super, Super_R, Toggle overview, global, quickshell:overviewToggleRelease # [hidden] Toggle overview/launcher +bindid = Super, Super_L, Toggle search, global, quickshell:searchToggleRelease # Toggle search +bindid = Super, Super_R, Toggle search, global, quickshell:searchToggleRelease # [hidden] Toggle search bind = Super, Super_L, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback) bind = Super, Super_R, exec, qs -c $qsConfig ipc call TEST_ALIVE || pkill fuzzel || fuzzel # [hidden] Launcher (fallback) -binditn = Super, catchall, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Ctrl, Super_L, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Ctrl, Super_R, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:272, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:273, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:274, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:275, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:276, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse:277, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse_up, global, quickshell:overviewToggleReleaseInterrupt # [hidden] -bind = Super, mouse_down,global, quickshell:overviewToggleReleaseInterrupt # [hidden] +binditn = Super, catchall, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Ctrl, Super_L, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Ctrl, Super_R, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:272, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:273, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:274, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:275, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:276, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse:277, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse_up, global, quickshell:searchToggleReleaseInterrupt # [hidden] +bind = Super, mouse_down,global, quickshell:searchToggleReleaseInterrupt # [hidden] bindit = ,Super_L, global, quickshell:workspaceNumber # [hidden] bindit = ,Super_R, global, quickshell:workspaceNumber # [hidden] +bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # Toggle overview bindd = Super, V, Clipboard history >> clipboard, global, quickshell:overviewClipboardToggle # Clipboard history >> clipboard bindd = Super, Period, Emoji >> clipboard, global, quickshell:overviewEmojiToggle # Emoji >> clipboard -bind = Super, Tab, global, quickshell:overviewWorkspacesToggle # [hidden] Toggle overview/launcher (alt) bind = Super, A, global, quickshell:sidebarLeftToggle # Toggle left sidebar bind = Super+Alt, A, global, quickshell:sidebarLeftToggleDetach # [hidden] bind = Super, B, global, quickshell:sidebarLeftToggle # [hidden] @@ -218,8 +218,8 @@ submap = global #! # Testing -bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder: \"Testing" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden] -bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Open profile image" -A "action2=Useless button" -A "action3=Cry more"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden] +bind = Super+Alt, f11, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification with body image" "This notification should contain your user account image and Discord icon. Oh and here is a random image in your Pictures folder: \"Testing" -a "Hyprland keybind" -p -h "string:image-path:/var/lib/AccountsService/icons/$USER" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Open the random image" -A "action3=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"; [[ $ACTION == *action2 ]] && xdg-open \"$RANDOM_IMAGE\"' # [hidden] +bind = Super+Alt, f12, exec, bash -c 'RANDOM_IMAGE=$(find ~/Pictures -type f | grep -v -i "nipple" | grep -v -i "pussy" | shuf -n 1); ACTION=$(notify-send "Test notification" "This notification should contain a random image in your Pictures folder and Discord icon.\nFlick right to dismiss!" -a "Discord (fake)" -p -h "string:image-path:$RANDOM_IMAGE" -t 6000 -i "discord" -A "openImage=Profile image" -A "action2=Useless button"); [[ $ACTION == *openImage ]] && xdg-open "/var/lib/AccountsService/icons/$USER"' # [hidden] bind = Super+Alt, Equal, exec, notify-send "Urgent notification" "Ah hell no" -u critical -a 'Hyprland keybind' # [hidden] ##! Session diff --git a/dots/.config/quickshell/ii/GlobalStates.qml b/dots/.config/quickshell/ii/GlobalStates.qml index 972495c64..85a0414d6 100644 --- a/dots/.config/quickshell/ii/GlobalStates.qml +++ b/dots/.config/quickshell/ii/GlobalStates.qml @@ -20,6 +20,7 @@ Singleton { property bool overlayOpen: false property bool overviewOpen: false property bool regionSelectorOpen: false + property bool searchOpen: false property bool screenLocked: false property bool screenLockContainsCharacters: false property bool screenUnlockFailed: false diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg new file mode 100644 index 000000000..2cfa6dba7 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/power-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/power.svg b/dots/.config/quickshell/ii/assets/icons/fluent/power.svg new file mode 100644 index 000000000..5c28fe986 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/power.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg index af58d933f..84f42c500 100644 --- a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg +++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-dark.svg @@ -26,8 +26,8 @@ inkscape:zoom="4.65625" inkscape:cx="32" inkscape:cy="32" - inkscape:window-width="1197" - inkscape:window-height="1020" + inkscape:window-width="1595" + inkscape:window-height="664" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" @@ -48,10 +48,10 @@ diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg index 8d0e69fce..76af86e67 100644 --- a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg +++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-checked-light.svg @@ -23,10 +23,10 @@ inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:zoom="6.5849319" - inkscape:cx="26.95548" + inkscape:cx="27.031411" inkscape:cy="26.423963" - inkscape:window-width="1257" - inkscape:window-height="1020" + inkscape:window-width="1621" + inkscape:window-height="820" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" @@ -35,10 +35,10 @@ id="defs2"> diff --git a/dots/.config/quickshell/ii/modules/common/Directories.qml b/dots/.config/quickshell/ii/modules/common/Directories.qml index 56f647684..9afbed44b 100644 --- a/dots/.config/quickshell/ii/modules/common/Directories.qml +++ b/dots/.config/quickshell/ii/modules/common/Directories.qml @@ -1,6 +1,7 @@ pragma Singleton pragma ComponentBehavior: Bound +import qs.services import qs.modules.common.functions import QtCore import QtQuick @@ -46,6 +47,9 @@ Singleton { property string aiChats: FileUtils.trimFileProtocol(`${Directories.state}/user/ai/chats`) property string aiTranslationScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/ai/gemini-translate.sh`) property string recordScriptPath: FileUtils.trimFileProtocol(`${Directories.scriptPath}/videos/record.sh`) + property string userAvatarPathAccountsService: FileUtils.trimFileProtocol(`/var/lib/AccountsService/icons/${SystemInfo.username}`) + property string userAvatarPathRicersAndWeirdSystems: FileUtils.trimFileProtocol(`${Directories.home}.face`) + property string userAvatarPathRicersAndWeirdSystems2: FileUtils.trimFileProtocol(`${Directories.home}.face.icon`) // Cleanup on init Component.onCompleted: { Quickshell.execDetached(["mkdir", "-p", `${shellConfig}`]) diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml index c360b536c..17dfc56c4 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledImage.qml @@ -12,4 +12,14 @@ Image { Behavior on opacity { animation: Appearance.animation.elementMoveEnter.numberAnimation.createObject(this) } + + property list fallbacks: [] + property int currentFallbackIndex: 0 + + onStatusChanged: { + if (status === Image.Error && currentFallbackIndex < fallbacks.length) { + source = fallbacks[currentFallbackIndex]; + currentFallbackIndex += 1; + } + } } diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml index 53797fb66..4688b29be 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledToolTip.qml @@ -20,6 +20,7 @@ ToolTip { hintingPreference: Font.PreferNoHinting // Prevent shaky text } + delay: 0 visible: internalVisibleCondition contentItem: StyledToolTipContent { diff --git a/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml b/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml index 248b46b56..c435f7f8a 100644 --- a/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml +++ b/dots/.config/quickshell/ii/modules/ii/overview/Overview.qml @@ -162,7 +162,7 @@ Scope { } IpcHandler { - target: "overview" + target: "search" function toggle() { GlobalStates.overviewOpen = !GlobalStates.overviewOpen; @@ -185,8 +185,8 @@ Scope { } GlobalShortcut { - name: "overviewToggle" - description: "Toggles overview on press" + name: "searchToggle" + description: "Toggles search on press" onPressed: { GlobalStates.overviewOpen = !GlobalStates.overviewOpen; @@ -201,16 +201,8 @@ Scope { } } GlobalShortcut { - name: "overviewClose" - description: "Closes overview" - - onPressed: { - GlobalStates.overviewOpen = false; - } - } - GlobalShortcut { - name: "overviewToggleRelease" - description: "Toggles overview on release" + name: "searchToggleRelease" + description: "Toggles search on release" onPressed: { GlobalStates.superReleaseMightTrigger = true; @@ -225,8 +217,8 @@ Scope { } } GlobalShortcut { - name: "overviewToggleReleaseInterrupt" - description: "Interrupts possibility of overview being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything." + name: "searchToggleReleaseInterrupt" + description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything." onPressed: { GlobalStates.superReleaseMightTrigger = false; diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml index 20af517fe..440695a2e 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml @@ -66,7 +66,7 @@ BarButton { } } - AppIcon { + WAppIcon { id: iconWidget anchors.centerIn: parent iconName: root.iconName diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml index 5ec96eeb4..a92a85578 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml @@ -14,8 +14,9 @@ AppButton { leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0 iconName: down ? "start-here-pressed" : "start-here" + checked: GlobalStates.searchOpen onClicked: { - GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... + GlobalStates.searchOpen = !GlobalStates.searchOpen; } BarToolTip { diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml index 51a3175bc..c1c16096b 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml @@ -42,7 +42,7 @@ AppButton { } spacing: 6 - AppIcon { + WAppIcon { id: iconWidget anchors.verticalCenter: parent.verticalCenter iconName: root.iconName diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml index 2839a6747..9f114609f 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml +++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml @@ -43,7 +43,7 @@ Button { Layout.fillHeight: false spacing: 8 - AppIcon { + WAppIcon { id: appIcon Layout.leftMargin: Looks.radius.large - root.padding + 2 Layout.alignment: Qt.AlignVCenter diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml index a321fa98e..609c9877b 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml @@ -54,6 +54,7 @@ Singleton { property color controlFg: "#FFFFFF" property color accentUnfocused: "#848484" property color link: "#235CCF" + property color inputBg: ColorUtils.transparentize(bg0, 0.4) } darkColors: QtObject { id: darkColors @@ -71,7 +72,7 @@ Singleton { property color bg2: '#8a8a8a' property color bg2Hover: '#b1b1b1' property color bg2Active: '#919191' - property color bg2Border: '#c4c4c4' + property color bg2Border: '#bdbdbd' property color subfg: "#CED1D7" property color fg: "#FFFFFF" property color fg1: "#D1D1D1" @@ -82,6 +83,7 @@ Singleton { property color controlFg: "#454545" property color accentUnfocused: "#989898" property color link: "#A7C9FC" + property color inputBg: ColorUtils.transparentize(darkColors.bg0, 0.5) } colors: QtObject { id: colors @@ -112,6 +114,7 @@ Singleton { property color controlBg: root.dark ? root.darkColors.controlBg : root.lightColors.controlBg property color controlBgHover: root.dark ? root.darkColors.controlBgHover : root.lightColors.controlBgHover property color controlFg: root.dark ? root.darkColors.controlFg : root.lightColors.controlFg + property color inputBg: root.dark ? root.darkColors.inputBg : root.lightColors.inputBg property color link: root.dark ? root.darkColors.link : root.lightColors.link property color danger: "#C42B1C" property color dangerActive: "#B62D1F" @@ -121,6 +124,7 @@ Singleton { property color accentActive: Appearance.colors.colPrimaryActive property color accentUnfocused: root.dark ? root.darkColors.accentUnfocused : root.lightColors.accentUnfocused property color accentFg: ColorUtils.isDark(accent) ? "#FFFFFF" : "#000000" + property color selection: Appearance.colors.colPrimaryContainer } radius: QtObject { diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml similarity index 94% rename from dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml rename to dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml index 48ff26104..6f71c65bb 100644 --- a/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WAppIcon.qml @@ -2,7 +2,6 @@ import QtQuick import org.kde.kirigami as Kirigami import qs.services import qs.modules.common -import qs.modules.waffle.looks Kirigami.Icon { id: root diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml index 6b2bc4ecb..ceed470ba 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WButton.qml @@ -53,10 +53,11 @@ Button { // Hover stuff signal hoverTimedOut property bool shouldShowTooltip: false + ToolTip.delay: 400 property Timer hoverTimer: Timer { id: hoverTimer running: root.hovered - interval: 400 + interval: root.ToolTip.delay onTriggered: { root.hoverTimedOut(); } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml new file mode 100644 index 000000000..a3f3e8a40 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WTextInput.qml @@ -0,0 +1,18 @@ +import QtQuick +import QtQuick.Controls + +TextInput { + id: root + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + color: Looks.colors.fg + + font { + hintingPreference: Font.PreferFullHinting + family: Looks.font.family.ui + pixelSize: Looks.font.pixelSize.large + weight: Looks.font.weight.regular + } + + selectionColor: Looks.colors.selection +} diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml index 47ad2f92d..f49477988 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/NotificationCenterContent.qml @@ -68,9 +68,8 @@ WBarAttachedPanelContent { WPane { id: calendarPane - contentItem: ColumnLayout { + contentItem: WPanelPageColumn { id: calendarColumnLayout - spacing: 0 DateHeader { Layout.fillWidth: true Synchronizer on collapsed { diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml index 856ddb160..895ab6892 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WSingleNotification.qml @@ -13,7 +13,7 @@ MouseArea { id: root required property var notification - property bool expanded: false + property bool expanded: notification.actions.length > 0 property string groupExpandControlMessage: "" signal groupExpandToggle hoverEnabled: true @@ -58,13 +58,19 @@ MouseArea { Loader { id: imageLoader + anchors { + top: parent.top + left: parent.left + } active: root.notification.image != "" sourceComponent: StyledImage { - width: 48 - height: 48 - sourceSize.width: width - sourceSize.height: height + readonly property int size: 48 + width: size + height: size + sourceSize.width: size + sourceSize.height: size source: root.notification.image + fillMode: Image.PreserveAspectFit } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml new file mode 100644 index 000000000..6bd23ae9b --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml @@ -0,0 +1,84 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +FooterRectangle { + id: root + + property bool searching: text.length > 0 + property alias text: searchInput.text + + Component.onCompleted: searchInput.forceActiveFocus() + + focus: true + color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter + + implicitWidth: 832 // TODO: Make sizes naturally inferred + implicitHeight: 63 + + Rectangle { + id: outline + anchors { + fill: parent + leftMargin: 32 + rightMargin: 32 + topMargin: 16 + bottomMargin: 15 + } + color: "transparent" + radius: height / 2 + border.width: 1 + border.color: Looks.colors.bg2Border + } + + Rectangle { + id: searchInputBg + anchors.fill: outline + anchors.margins: 1 + radius: height / 2 + color: Looks.colors.inputBg + + RowLayout { + anchors.fill: parent + spacing: 11 + + WAppIcon { + Layout.leftMargin: 14 + iconName: "system-search-checked" + separateLightDark: true + implicitSize: 18 + } + + WTextInput { + id: searchInput + focus: true + Layout.fillWidth: true + + WText { + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + color: Looks.colors.accentUnfocused + text: Translation.tr("Search for apps") // should also have "", settings, and documents" but we don't have those + visible: searchInput.text.length === 0 + font.pixelSize: Looks.font.pixelSize.large + } + } + } + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.IBeamCursor + acceptedButtons: Qt.NoButton + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml new file mode 100644 index 000000000..cdbb7d3b8 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml @@ -0,0 +1,16 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +BodyRectangle { + id: root + + +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml new file mode 100644 index 000000000..6e97f88be --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml @@ -0,0 +1,39 @@ +pragma ComponentBehavior: Bound +import Qt.labs.synchronizer +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +WBarAttachedPanelContent { + id: root + + property bool searching: false + property string searchText: "" + + contentItem: WPane { + contentItem: WPanelPageColumn { + SearchBar { + focus: true + Layout.fillWidth: true + Synchronizer on searching { + property alias target: root.searching + } + Synchronizer on text { + property alias source: root.searchText + } + } + Loader { + id: pageContentLoader + Layout.fillWidth: true + source: root.searching ? "SearchPageContent.qml" : "StartPageContent.qml" + } + } + } + +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml new file mode 100644 index 000000000..36e605187 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml @@ -0,0 +1,98 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import org.kde.kirigami as Kirigami +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +WPanelPageColumn { + id: root + + WPanelSeparator {} + + BodyRectangle { + implicitHeight: 736 // TODO: Make sizes naturally inferred + } + + WPanelSeparator {} + + StartFooter { + Layout.fillWidth: true + } + + component StartFooter: FooterRectangle { + implicitHeight: 63 + + UserButton { + anchors { + left: parent.left + leftMargin: 52 + bottom: parent.bottom + bottomMargin: 12 + } + } + + PowerButton { + anchors { + right: parent.right + rightMargin: 52 + bottom: parent.bottom + bottomMargin: 12 + } + } + } + + component UserButton: WBorderlessButton { + id: userButton + implicitWidth: userButtonRow.implicitWidth + 12 * 2 + implicitHeight: 40 + + contentItem: Item { + RowLayout { + id: userButtonRow + anchors.centerIn: parent + spacing: 12 + + StyledImage { + id: avatar + // Use this for free fallback because I'm lazy + Layout.alignment: Qt.AlignTop + sourceSize: Qt.size(32, 32) + source: Directories.userAvatarPathAccountsService + fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2] + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Circle { + diameter: avatar.height + } + } + } + WText { + Layout.alignment: Qt.AlignVCenter + text: SystemInfo.username + } + } + } + } + + component PowerButton: WBorderlessButton { + implicitWidth: 40 + implicitHeight: 40 + + contentItem: Item { + FluentIcon { + anchors.centerIn: parent + icon: "power" + implicitSize: 20 + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml new file mode 100644 index 000000000..9b59fb0c8 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml @@ -0,0 +1,119 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets + +Scope { + id: root + + Connections { + target: GlobalStates + + function onSearchOpenChanged() { + if (GlobalStates.searchOpen) + panelLoader.active = true; + } + } + + Loader { + id: panelLoader + active: GlobalStates.searchOpen + sourceComponent: PanelWindow { + id: panelWindow + exclusiveZone: 0 + WlrLayershell.namespace: "quickshell:wStartMenu" + WlrLayershell.keyboardFocus: WlrKeyboardFocus.OnDemand + color: "transparent" + + anchors { + bottom: Config.options.waffles.bar.bottom + top: !Config.options.waffles.bar.bottom + left: Config.options.waffles.bar.leftAlignApps + } + + implicitWidth: content.implicitWidth + implicitHeight: content.implicitHeight + + HyprlandFocusGrab { + id: focusGrab + active: true + windows: [panelWindow] + onCleared: content.close() + } + + Connections { + target: GlobalStates + function onSearchOpenChanged() { + if (!GlobalStates.searchOpen) + content.close(); + } + } + + StartMenuContent { + id: content + anchors.fill: parent + focus: true + + onClosed: { + GlobalStates.searchOpen = false; + panelLoader.active = false; + } + } + } + } + + IpcHandler { + target: "search" + + function toggle() { + GlobalStates.searchOpen = !GlobalStates.searchOpen; + } + function close() { + GlobalStates.searchOpen = false; + } + function open() { + GlobalStates.searchOpen = true; + } + function toggleReleaseInterrupt() { + GlobalStates.superReleaseMightTrigger = false; + } + } + + GlobalShortcut { + name: "searchToggle" + description: "Toggles search on press" + + onPressed: { + GlobalStates.searchOpen = !GlobalStates.searchOpen; + } + } + GlobalShortcut { + name: "searchToggleRelease" + description: "Toggles search on release" + + onPressed: { + GlobalStates.superReleaseMightTrigger = true; + } + + onReleased: { + if (!GlobalStates.superReleaseMightTrigger) { + GlobalStates.superReleaseMightTrigger = true; + return; + } + GlobalStates.searchOpen = !GlobalStates.searchOpen; + } + } + GlobalShortcut { + name: "searchToggleReleaseInterrupt" + description: "Interrupts possibility of search being toggled on release. " + "This is necessary because GlobalShortcut.onReleased in quickshell triggers whether or not you press something else while holding the key. " + "To make sure this works consistently, use binditn = MODKEYS, catchall in an automatically triggered submap that includes everything." + + onPressed: { + GlobalStates.superReleaseMightTrigger = false; + } + } +} diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml index 3f57c0c28..7bb565d11 100644 --- a/dots/.config/quickshell/ii/shell.qml +++ b/dots/.config/quickshell/ii/shell.qml @@ -33,6 +33,7 @@ import qs.modules.waffle.background import qs.modules.waffle.bar import qs.modules.waffle.notificationCenter import qs.modules.waffle.onScreenDisplay +import qs.modules.waffle.startMenu import QtQuick import QtQuick.Window @@ -77,11 +78,13 @@ ShellRoot { PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} } PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} } PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} } + PanelLoader { identifier: "wActionCenter"; component: WaffleActionCenter {} } PanelLoader { identifier: "wBar"; component: WaffleBar {} } PanelLoader { identifier: "wBackground"; component: WaffleBackground {} } PanelLoader { identifier: "wNotificationCenter"; component: WaffleNotificationCenter {} } PanelLoader { identifier: "wOnScreenDisplay"; component: WaffleOSD {} } + PanelLoader { identifier: "wStartMenu"; component: WaffleStartMenu {} } ReloadPopup {} component PanelLoader: LazyLoader { @@ -94,7 +97,7 @@ ShellRoot { property list families: ["ii", "waffle"] property var panelFamilies: ({ "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], - "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"], + "waffle": ["wActionCenter", "wBar", "wBackground", "wNotificationCenter", "wOnScreenDisplay", "wStartMenu", "iiCheatsheet", "iiLock", "iiNotificationPopup", "iiOnScreenKeyboard", "iiOverlay", "iiPolkit", "iiRegionSelector", "iiSessionScreen", "iiWallpaperSelector"], }) function cyclePanelFamily() { const currentIndex = families.indexOf(Config.options.panelFamily) From b45f2dd235f1e4e868d5748688ea4e23088c4f30 Mon Sep 17 00:00:00 2001 From: jwihardi Date: Sun, 30 Nov 2025 15:31:02 -0500 Subject: [PATCH 09/16] added libqalculate gentoo --- ...ets-1.0-r3.ebuild => illogical-impulse-widgets-1.0-r4.ebuild} | 1 + 1 file changed, 1 insertion(+) rename sdata/dist-gentoo/illogical-impulse-widgets/{illogical-impulse-widgets-1.0-r3.ebuild => illogical-impulse-widgets-1.0-r4.ebuild} (95%) diff --git a/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild b/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild similarity index 95% rename from sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild rename to sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild index 95ffeffba..9ffceea09 100644 --- a/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r3.ebuild +++ b/sdata/dist-gentoo/illogical-impulse-widgets/illogical-impulse-widgets-1.0-r4.ebuild @@ -21,6 +21,7 @@ RDEPEND=" app-misc/songrec app-i18n/translate-shell gui-apps/wlogout + sci-libs/libqalculate " ##### CUSTOM EBUILDS # app-misc/songrec From 8d2c8bd38ee48e96c7751ffaf3595e5056a460e3 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:27:01 +0100 Subject: [PATCH 10/16] waffles: power menu and user account menu --- .../ii/assets/icons/fluent/corporation.svg | 17 ++ .../icons/fluent/start-here-pressed.svg | 142 +++++++++++++--- .../ii/assets/icons/fluent/start-here.svg | 142 +++++++++++++--- .../quickshell/ii/modules/common/Config.qml | 1 + .../ii/modules/waffle/looks/WIcons.qml | 4 + .../ii/modules/waffle/looks/WMenu.qml | 83 +++++++++ .../ii/modules/waffle/looks/WMenuItem.qml | 93 +++++++++++ .../ii/modules/waffle/looks/WPane.qml | 2 +- .../ii/modules/waffle/looks/WToolTip.qml | 2 + .../modules/waffle/looks/WToolTipContent.qml | 1 + .../ii/modules/waffle/looks/WUserAvatar.qml | 27 +++ .../notificationCenter/WNotificationGroup.qml | 1 + .../waffle/startMenu/StartPageContent.qml | 157 ++++++++++++++++-- 13 files changed, 611 insertions(+), 61 deletions(-) create mode 100644 dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WMenuItem.qml create mode 100644 dots/.config/quickshell/ii/modules/waffle/looks/WUserAvatar.qml diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg b/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg new file mode 100644 index 000000000..0ed1a0319 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/corporation.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg b/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg index e6b950eca..2efc81c45 100644 --- a/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg +++ b/dots/.config/quickshell/ii/assets/icons/fluent/start-here-pressed.svg @@ -1,24 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/start-here.svg b/dots/.config/quickshell/ii/assets/icons/fluent/start-here.svg index 708d5a71b..9f7b4a177 100644 --- a/dots/.config/quickshell/ii/assets/icons/fluent/start-here.svg +++ b/dots/.config/quickshell/ii/assets/icons/fluent/start-here.svg @@ -1,24 +1,120 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index 1716aa2ef..6331df0b1 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -153,6 +153,7 @@ Singleton { property JsonObject apps: JsonObject { property string bluetooth: "kcmshell6 kcm_bluetooth" + property string manageUser: "kcmshell6 kcm_users" property string network: "kitty -1 fish -c nmtui" property string networkEthernet: "kcmshell6 kcm_networkmanagement" property string taskManager: "plasma-systemmonitor --page-name Processes" diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml index 1d24170bc..7fe121165 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml @@ -7,6 +7,10 @@ import qs.services Singleton { id: root + function pathForName(iconName) { + return Quickshell.shellPath(`assets/icons/fluent/${iconName}.svg`); + } + function wifiIconForStrength(strength) { if (strength > 75) return "wifi-1"; diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml new file mode 100644 index 000000000..a208f355b --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WMenu.qml @@ -0,0 +1,83 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Hyprland +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +Menu { + id: root + + property bool downDirection: false + property bool hasIcons: false // TODO: implement + + implicitWidth: background.implicitWidth + root.padding * 2 + implicitHeight: background.implicitHeight + root.padding * 2 + padding: 3 + property real sourceEdgeMargin: -implicitHeight + clip: true + + enter: Transition { + NumberAnimation { + property: "sourceEdgeMargin" + from: -root.implicitHeight + to: root.padding + duration: 200 + easing.type: Easing.BezierSpline + easing.bezierCurve: Looks.transition.easing.bezierCurve.easeIn + } + } + exit: Transition { + NumberAnimation { + property: "sourceEdgeMargin" + from: root.padding + to: -root.implicitHeight + duration: 150 + easing.type: Easing.BezierSpline + easing.bezierCurve: Looks.transition.easing.bezierCurve.easeOut + } + } + + background: WPane { + anchors { + left: parent.left + right: parent.right + top: root.downDirection ? parent.top : undefined + bottom: root.downDirection ? undefined : parent.bottom + margins: root.padding + topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding + bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin + } + contentItem: Rectangle { + color: Looks.colors.bg1Base + implicitWidth: menuListView.implicitWidth + root.padding * 2 + implicitHeight: root.contentItem.implicitHeight + root.padding * 2 + } + } + + contentItem: ListView { + id: menuListView + anchors { + left: parent.left + right: parent.right + top: root.downDirection ? parent.top : undefined + bottom: root.downDirection ? undefined : parent.bottom + margins: root.padding * 2 + topMargin: root.downDirection ? root.sourceEdgeMargin : root.padding + bottomMargin: root.downDirection ? root.padding : root.sourceEdgeMargin + } + implicitHeight: contentHeight + implicitWidth: Array.from({ + length: count + }, (_, i) => itemAtIndex(i)?.implicitWidth ?? 0).reduce((a, b) => a > b ? a : b) + + model: root.contentModel + } + + delegate: WMenuItem { + id: menuItemDelegate + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WMenuItem.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WMenuItem.qml new file mode 100644 index 000000000..3030bc122 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WMenuItem.qml @@ -0,0 +1,93 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import Quickshell.Hyprland +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +MenuItem { + id: root + + property color colBackground: ColorUtils.transparentize(Looks.colors.bg1) + property color colBackgroundHover: Looks.colors.bg2Hover + property color colBackgroundActive: Looks.colors.bg2Active + property color colBackgroundToggled: Looks.colors.accent + property color colBackgroundToggledHover: Looks.colors.accentHover + property color colBackgroundToggledActive: Looks.colors.accentActive + property color colForeground: Looks.colors.fg + property color colForegroundToggled: Looks.colors.accentFg + property color colForegroundDisabled: ColorUtils.transparentize(Looks.colors.subfg, 0.4) + property color color: { + if (!root.enabled) + return colBackground; + if (root.checked) { + if (root.down) { + return root.colBackgroundToggledActive; + } else if (root.hovered) { + return root.colBackgroundToggledHover; + } else { + return root.colBackgroundToggled; + } + } + if (root.down) { + return root.colBackgroundActive; + } else if (root.hovered) { + return root.colBackgroundHover; + } else { + return root.colBackground; + } + } + property color fgColor: { + if (root.checked) + return root.colForegroundToggled; + if (root.enabled) + return root.colForeground; + return root.colForegroundDisabled; + } + + property real inset: 2 + topInset: inset + bottomInset: inset + leftInset: inset + rightInset: inset + horizontalPadding: 11 + + background: Rectangle { + id: backgroundRect + radius: Looks.radius.medium + color: root.color + Behavior on color { + animation: Looks.transition.color.createObject(this) + } + } + + implicitHeight: Math.max(28, contentItem.implicitHeight) + topInset + bottomInset + implicitWidth: contentItem.implicitWidth + leftInset + rightInset + leftPadding + rightPadding + + contentItem: RowLayout { + id: contentLayout + spacing: 12 + FluentIcon { + id: buttonIcon + monochrome: true + implicitSize: 20 + Layout.fillWidth: false + Layout.alignment: Qt.AlignVCenter + color: root.fgColor + visible: root.icon.name !== ""; + icon: root.icon.name + } + WText { + id: buttonText + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft + text: root.text + horizontalAlignment: Text.AlignLeft + font.pixelSize: Looks.font.pixelSize.large + color: root.fgColor + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml index be75cc30a..f281a8b7c 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPane.qml @@ -10,7 +10,7 @@ import qs.modules.waffle.looks Item { id: root - required property Item contentItem + property Item contentItem property real radius: Looks.radius.large property alias border: borderRect property alias borderColor: borderRect.border.color diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WToolTip.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WToolTip.qml index 3c8d20d26..7368836cc 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WToolTip.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WToolTip.qml @@ -25,6 +25,8 @@ StyledToolTip { verticalPadding: 8 horizontalPadding: 10 + delay: 400 + contentItem: WToolTipContent { id: tooltipContent realContentItem: root.realContentItem diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WToolTipContent.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WToolTipContent.qml index 13c78fc7e..b0a400df0 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WToolTipContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WToolTipContent.qml @@ -6,6 +6,7 @@ Item { id: root anchors.centerIn: parent required property Item realContentItem + property alias radius: realContent.radius property real verticalPadding: 8 property real horizontalPadding: 10 implicitWidth: realContent.implicitWidth + 2 * 2 diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WUserAvatar.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WUserAvatar.qml new file mode 100644 index 000000000..07499d51b --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WUserAvatar.qml @@ -0,0 +1,27 @@ +pragma ComponentBehavior: Bound +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +StyledImage { + id: avatar + Layout.alignment: Qt.AlignTop + sourceSize: Qt.size(32, 32) + source: Directories.userAvatarPathAccountsService + fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2] + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Circle { + diameter: avatar.height + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml index 122469771..658bc03ae 100644 --- a/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml +++ b/dots/.config/quickshell/ii/modules/waffle/notificationCenter/WNotificationGroup.qml @@ -7,6 +7,7 @@ import qs.modules.common.widgets import qs.modules.common.functions import qs.modules.waffle.looks +// TODO: Swipe to dismiss MouseArea { id: root diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml index 36e605187..eb3c96a80 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartPageContent.qml @@ -4,7 +4,6 @@ import QtQuick.Controls import QtQuick.Layouts import Qt5Compat.GraphicalEffects import Quickshell -import org.kde.kirigami as Kirigami import qs import qs.services import qs.modules.common @@ -60,20 +59,8 @@ WPanelPageColumn { anchors.centerIn: parent spacing: 12 - StyledImage { - id: avatar - // Use this for free fallback because I'm lazy - Layout.alignment: Qt.AlignTop + WUserAvatar { sourceSize: Qt.size(32, 32) - source: Directories.userAvatarPathAccountsService - fallbacks: [Directories.userAvatarPathRicersAndWeirdSystems, Directories.userAvatarPathRicersAndWeirdSystems2] - - layer.enabled: true - layer.effect: OpacityMask { - maskSource: Circle { - diameter: avatar.height - } - } } WText { Layout.alignment: Qt.AlignVCenter @@ -81,9 +68,116 @@ WPanelPageColumn { } } } + + onClicked: { + userMenu.open(); + } + + WToolTip { + text: SystemInfo.username + } + + Popup { + id: userMenu + x: -51 + y: -userMenu.implicitHeight + userButton.implicitHeight / 2 - 10 + + background: null + + WToolTipContent { + id: popupContent + horizontalPadding: 10 + verticalPadding: 7 + radius: Looks.radius.large + realContentItem: Item { + implicitWidth: userMenuContentLayout.implicitWidth + implicitHeight: userMenuContentLayout.implicitHeight + + ColumnLayout { + id: userMenuContentLayout + anchors { + fill: parent + leftMargin: popupContent.horizontalPadding + rightMargin: popupContent.horizontalPadding + topMargin: popupContent.verticalPadding + bottomMargin: popupContent.verticalPadding + } + spacing: 5 + + RowLayout { + Layout.fillWidth: true + Layout.leftMargin: 6 + FluentIcon { + Layout.alignment: Qt.AlignVCenter + implicitSize: 22 + icon: "corporation" + monochrome: false + } + WText { + Layout.alignment: Qt.AlignVCenter + text: "Megahard" + font.pixelSize: Looks.font.pixelSize.large + font.weight: Looks.font.weight.strong + } + Item { Layout.fillWidth: true } + WBorderlessButton { + Layout.alignment: Qt.AlignVCenter + implicitHeight: 36 + implicitWidth: textItem.implicitWidth + 10 * 2 + contentItem: WText { + id: textItem + text: Translation.tr("Sign out") + font.pixelSize: Looks.font.pixelSize.large + } + onClicked: Session.logout() + } + } + Item { // Force min width 360 (using min on the item somehow doesn't work) + implicitWidth: 334 + } + RowLayout { + Layout.fillWidth: true + Layout.bottomMargin: 7 + Layout.leftMargin: 6 + spacing: 12 + WUserAvatar { + sourceSize: Qt.size(58, 58) + } + ColumnLayout { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + spacing: 2 + WText { + text: SystemInfo.username + font.pixelSize: Looks.font.pixelSize.larger + font.weight: Looks.font.weight.strong + } + WText { + color: Looks.colors.fg1 + text: Translation.tr("Local account") + } + WText { + color: Looks.colors.accent + text: Translation.tr("Manage my account") + MouseArea { + anchors.fill: parent + cursorShape: Qt.PointingHandCursor + onClicked: { + Quickshell.execDetached(["bash", "-c", Config.options.apps.manageUser]) + GlobalStates.searchOpen = false; + } + } + } + } + } + } + } + } + } } component PowerButton: WBorderlessButton { + id: powerButton implicitWidth: 40 implicitHeight: 40 @@ -94,5 +188,40 @@ WPanelPageColumn { implicitSize: 20 } } + + WToolTip { + extraVisibleCondition: !powerMenu.visible + text: qsTr("Power") + } + + onClicked: { + powerMenu.open() + } + + WMenu { + id: powerMenu + x: -powerMenu.implicitWidth / 2 + powerButton.implicitWidth / 2 + y: -powerMenu.implicitHeight - 4 + Action { + icon.name: "lock-closed" + text: Translation.tr("Lock") + onTriggered: Session.lock() + } + Action { + icon.name: "weather-moon" + text: Translation.tr("Sleep") + onTriggered: Session.suspend() + } + Action { + icon.name: "power" + text: Translation.tr("Shut down") + onTriggered: Session.poweroff() + } + Action { + icon.name: "arrow-counterclockwise" + text: Translation.tr("Restart") + onTriggered: Session.reboot() + } + } } } From 4cad401ea6ceccb6f83426c9ed9198908d67d4b6 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:28:41 +0100 Subject: [PATCH 11/16] add layerrules for more waffles stuff --- dots/.config/hypr/hyprland/rules.conf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dots/.config/hypr/hyprland/rules.conf b/dots/.config/hypr/hyprland/rules.conf index 17a4d5af9..cfb1e3f7b 100644 --- a/dots/.config/hypr/hyprland/rules.conf +++ b/dots/.config/hypr/hyprland/rules.conf @@ -159,7 +159,9 @@ layerrule = animation slide right, quickshell:sidebarRight layerrule = animation slide left, quickshell:sidebarLeft layerrule = animation slide, quickshell:verticalBar layerrule = animation slide top, quickshell:wallpaperSelector +layerrule = noanim, quickshell:wNotificationCenter layerrule = noanim, quickshell:wOnScreenDisplay +layerrule = noanim, quickshell:wStartMenu # Launchers need to be FAST layerrule = noanim, gtk4-layer-shell From 4ce4645749255f26ce642877d3470d277a2a98a0 Mon Sep 17 00:00:00 2001 From: end-4 <97237370+end-4@users.noreply.github.com> Date: Mon, 1 Dec 2025 22:00:36 +0100 Subject: [PATCH 12/16] move launcher search logic to a service --- .../ii/modules/ii/overview/SearchBar.qml | 2 +- .../ii/modules/ii/overview/SearchWidget.qml | 268 +---------------- .../quickshell/ii/services/LauncherSearch.qml | 278 ++++++++++++++++++ 3 files changed, 285 insertions(+), 263 deletions(-) create mode 100644 dots/.config/quickshell/ii/services/LauncherSearch.qml diff --git a/dots/.config/quickshell/ii/modules/ii/overview/SearchBar.qml b/dots/.config/quickshell/ii/modules/ii/overview/SearchBar.qml index 5cd7b9ac5..6a5de6a7e 100644 --- a/dots/.config/quickshell/ii/modules/ii/overview/SearchBar.qml +++ b/dots/.config/quickshell/ii/modules/ii/overview/SearchBar.qml @@ -81,7 +81,7 @@ RowLayout { } } - onTextChanged: root.searchingText = text + onTextChanged: LauncherSearch.query = text onAccepted: { if (appResults.count > 0) { diff --git a/dots/.config/quickshell/ii/modules/ii/overview/SearchWidget.qml b/dots/.config/quickshell/ii/modules/ii/overview/SearchWidget.qml index 03ebfce1b..c0ca28d62 100644 --- a/dots/.config/quickshell/ii/modules/ii/overview/SearchWidget.qml +++ b/dots/.config/quickshell/ii/modules/ii/overview/SearchWidget.qml @@ -14,81 +14,11 @@ import Quickshell.Io Item { // Wrapper id: root readonly property string xdgConfigHome: Directories.config - property string searchingText: "" + property string searchingText: LauncherSearch.query property bool showResults: searchingText != "" implicitWidth: searchWidgetContent.implicitWidth + Appearance.sizes.elevationMargin * 2 implicitHeight: searchBar.implicitHeight + searchBar.verticalPadding * 2 + Appearance.sizes.elevationMargin * 2 - property string mathResult: "" - property bool clipboardWorkSafetyActive: { - const enabled = Config.options.workSafety.enable.clipboard; - const sensitiveNetwork = (StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.workSafety.triggerCondition.networkNameKeywords)) - return enabled && sensitiveNetwork; - } - - property var searchActions: [ - { - action: "accentcolor", - execute: args => { - Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--noswitch", "--color", ...(args != '' ? [`${args}`] : [])]); - } - }, - { - action: "dark", - execute: () => { - Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]); - } - }, - { - action: "konachanwallpaper", - execute: () => { - Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")]); - } - }, - { - action: "light", - execute: () => { - Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]); - } - }, - { - action: "superpaste", - execute: args => { - if (!/^(\d+)/.test(args.trim())) { // Invalid if doesn't start with numbers - Quickshell.execDetached([ - "notify-send", - Translation.tr("Superpaste"), - Translation.tr("Usage: %1superpaste NUM_OF_ENTRIES[i]\nSupply i when you want images\nExamples:\n%1superpaste 4i for the last 4 images\n%1superpaste 7 for the last 7 entries").arg(Config.options.search.prefix.action), - "-a", "Shell" - ]); - return; - } - const syntaxMatch = /^(?:(\d+)(i)?)/.exec(args.trim()); - const count = syntaxMatch[1] ? parseInt(syntaxMatch[1]) : 1; - const isImage = !!syntaxMatch[2]; - Cliphist.superpaste(count, isImage); - } - }, - { - action: "todo", - execute: args => { - Todo.addTask(args); - } - }, - { - action: "wallpaper", - execute: () => { - GlobalStates.wallpaperSelectorOpen = true; - } - }, - { - action: "wipeclipboard", - execute: () => { - Cliphist.wipe(); - } - }, - ] - function focusFirstItem() { appResults.currentIndex = 0; } @@ -103,13 +33,13 @@ Item { // Wrapper function cancelSearch() { searchBar.searchInput.selectAll(); - root.searchingText = ""; + LauncherSearch.query = ""; searchBar.animateWidth = true; } function setSearchingText(text) { searchBar.searchInput.text = text; - root.searchingText = text; + LauncherSearch.query = text; } function containsUnsafeLink(entry) { @@ -118,34 +48,6 @@ Item { // Wrapper return StringUtils.stringListContainsSubstring(entry.toLowerCase(), unsafeKeywords); } - Timer { - id: nonAppResultsTimer - interval: Config.options.search.nonAppResultDelay - onTriggered: { - let expr = root.searchingText; - if (expr.startsWith(Config.options.search.prefix.math)) { - expr = expr.slice(Config.options.search.prefix.math.length); - } - mathProcess.calculateExpression(expr); - } - } - - Process { - id: mathProcess - property list baseCommand: ["qalc", "-t"] - function calculateExpression(expression) { - mathProcess.running = false; - mathProcess.command = baseCommand.concat(expression); - mathProcess.running = true; - } - stdout: SplitParser { - onRead: data => { - root.mathResult = data; - root.focusFirstItem(); - } - } - } - Keys.onPressed: event => { // Prevent Esc and Backspace from registering if (event.key === Qt.Key_Escape) @@ -285,167 +187,9 @@ Item { // Wrapper model: ScriptModel { id: model objectProp: "key" - values: { - // Search results are handled here - ////////////////// Skip? ////////////////// - if (root.searchingText == "") - return []; - - ///////////// Special cases /////////////// - if (root.searchingText.startsWith(Config.options.search.prefix.clipboard)) { - // Clipboard - const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.clipboard); - return Cliphist.fuzzyQuery(searchString).map((entry, index, array) => { - const mightBlurImage = Cliphist.entryIsImage(entry) && root.clipboardWorkSafetyActive; - let shouldBlurImage = mightBlurImage; - if (mightBlurImage) { - shouldBlurImage = shouldBlurImage && (containsUnsafeLink(array[index - 1]) || containsUnsafeLink(array[index + 1])); - } - const type = `#${entry.match(/^\s*(\S+)/)?.[1] || ""}` - return { - key: type, - cliphistRawString: entry, - name: StringUtils.cleanCliphistEntry(entry), - clickActionName: "", - type: type, - execute: () => { - Cliphist.copy(entry) - }, - actions: [ - { - name: "Copy", - materialIcon: "content_copy", - execute: () => { - Cliphist.copy(entry); - } - }, - { - name: "Delete", - materialIcon: "delete", - execute: () => { - Cliphist.deleteEntry(entry); - } - } - ], - blurImage: shouldBlurImage, - blurImageText: Translation.tr("Work safety") - }; - }).filter(Boolean); - } - else if (root.searchingText.startsWith(Config.options.search.prefix.emojis)) { - // Clipboard - const searchString = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.emojis); - return Emojis.fuzzyQuery(searchString).map(entry => { - const emoji = entry.match(/^\s*(\S+)/)?.[1] || "" - return { - key: emoji, - cliphistRawString: entry, - bigText: emoji, - name: entry.replace(/^\s*\S+\s+/, ""), - clickActionName: "", - type: "Emoji", - execute: () => { - Quickshell.clipboardText = entry.match(/^\s*(\S+)/)?.[1]; - } - }; - }).filter(Boolean); - } - - ////////////////// Init /////////////////// - nonAppResultsTimer.restart(); - const mathResultObject = { - key: `Math result: ${root.mathResult}`, - name: root.mathResult, - clickActionName: Translation.tr("Copy"), - type: Translation.tr("Math result"), - fontType: "monospace", - materialSymbol: 'calculate', - execute: () => { - Quickshell.clipboardText = root.mathResult; - } - }; - const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.app)).map(entry => { - entry.clickActionName = Translation.tr("Launch"); - entry.type = Translation.tr("App"); - entry.key = entry.execute - return entry; - }) - const commandResultObject = { - key: `cmd ${root.searchingText}`, - name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.shellCommand).replace("file://", ""), - clickActionName: Translation.tr("Run"), - type: Translation.tr("Run command"), - fontType: "monospace", - materialSymbol: 'terminal', - execute: () => { - let cleanedCommand = root.searchingText.replace("file://", ""); - cleanedCommand = StringUtils.cleanPrefix(cleanedCommand, Config.options.search.prefix.shellCommand); - if (cleanedCommand.startsWith(Config.options.search.prefix.shellCommand)) { - cleanedCommand = cleanedCommand.slice(Config.options.search.prefix.shellCommand.length); - } - Quickshell.execDetached(["bash", "-c", searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${cleanedCommand}'` : cleanedCommand]); - } - }; - const webSearchResultObject = { - key: `website ${root.searchingText}`, - name: StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch), - clickActionName: Translation.tr("Search"), - type: Translation.tr("Search the web"), - materialSymbol: 'travel_explore', - execute: () => { - let query = StringUtils.cleanPrefix(root.searchingText, Config.options.search.prefix.webSearch); - let url = Config.options.search.engineBaseUrl + query; - for (let site of Config.options.search.excludedSites) { - url += ` -site:${site}`; - } - Qt.openUrlExternally(url); - } - } - const launcherActionObjects = root.searchActions.map(action => { - const actionString = `${Config.options.search.prefix.action}${action.action}`; - if (actionString.startsWith(root.searchingText) || root.searchingText.startsWith(actionString)) { - return { - key: `Action ${actionString}`, - name: root.searchingText.startsWith(actionString) ? root.searchingText : actionString, - clickActionName: Translation.tr("Run"), - type: Translation.tr("Action"), - materialSymbol: 'settings_suggest', - execute: () => { - action.execute(root.searchingText.split(" ").slice(1).join(" ")); - } - }; - } - return null; - }).filter(Boolean); - - //////// Prioritized by prefix ///////// - let result = []; - const startsWithNumber = /^\d/.test(root.searchingText); - const startsWithMathPrefix = root.searchingText.startsWith(Config.options.search.prefix.math); - const startsWithShellCommandPrefix = root.searchingText.startsWith(Config.options.search.prefix.shellCommand); - const startsWithWebSearchPrefix = root.searchingText.startsWith(Config.options.search.prefix.webSearch); - if (startsWithNumber || startsWithMathPrefix) { - result.push(mathResultObject); - } else if (startsWithShellCommandPrefix) { - result.push(commandResultObject); - } else if (startsWithWebSearchPrefix) { - result.push(webSearchResultObject); - } - - //////////////// Apps ////////////////// - result = result.concat(appResultObjects); - - ////////// Launcher actions //////////// - result = result.concat(launcherActionObjects); - - /// Math result, command, web search /// - if (Config.options.search.prefix.showDefaultActionsWithoutPrefix) { - if (!startsWithShellCommandPrefix) result.push(commandResultObject); - if (!startsWithNumber && !startsWithMathPrefix) result.push(mathResultObject); - if (!startsWithWebSearchPrefix) result.push(webSearchResultObject); - } - - return result; + values: LauncherSearch.results + onValuesChanged: { + root.focusFirstItem(); } } diff --git a/dots/.config/quickshell/ii/services/LauncherSearch.qml b/dots/.config/quickshell/ii/services/LauncherSearch.qml new file mode 100644 index 000000000..bf23c1c48 --- /dev/null +++ b/dots/.config/quickshell/ii/services/LauncherSearch.qml @@ -0,0 +1,278 @@ +pragma Singleton + +import qs.modules.common +import qs.modules.common.models +import qs.modules.common.functions +import QtQuick +import QtQuick.Controls +import Quickshell +import Quickshell.Io + +Singleton { + id: root + + property string query: "" + property var searchActions: [ + { + action: "accentcolor", + execute: args => { + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--noswitch", "--color", ...(args != '' ? [`${args}`] : [])]); + } + }, + { + action: "dark", + execute: () => { + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "dark", "--noswitch"]); + } + }, + { + action: "konachanwallpaper", + execute: () => { + Quickshell.execDetached([Quickshell.shellPath("scripts/colors/random/random_konachan_wall.sh")]); + } + }, + { + action: "light", + execute: () => { + Quickshell.execDetached([Directories.wallpaperSwitchScriptPath, "--mode", "light", "--noswitch"]); + } + }, + { + action: "superpaste", + execute: args => { + if (!/^(\d+)/.test(args.trim())) { + // Invalid if doesn't start with numbers + Quickshell.execDetached(["notify-send", Translation.tr("Superpaste"), Translation.tr("Usage: %1superpaste NUM_OF_ENTRIES[i]\nSupply i when you want images\nExamples:\n%1superpaste 4i for the last 4 images\n%1superpaste 7 for the last 7 entries").arg(Config.options.search.prefix.action), "-a", "Shell"]); + return; + } + const syntaxMatch = /^(?:(\d+)(i)?)/.exec(args.trim()); + const count = syntaxMatch[1] ? parseInt(syntaxMatch[1]) : 1; + const isImage = !!syntaxMatch[2]; + Cliphist.superpaste(count, isImage); + } + }, + { + action: "todo", + execute: args => { + Todo.addTask(args); + } + }, + { + action: "wallpaper", + execute: () => { + GlobalStates.wallpaperSelectorOpen = true; + } + }, + { + action: "wipeclipboard", + execute: () => { + Cliphist.wipe(); + } + }, + ] + + property string mathResult: "" + property bool clipboardWorkSafetyActive: { + const enabled = Config.options.workSafety.enable.clipboard; + const sensitiveNetwork = (StringUtils.stringListContainsSubstring(Network.networkName.toLowerCase(), Config.options.workSafety.triggerCondition.networkNameKeywords)) + return enabled && sensitiveNetwork; + } + + function containsUnsafeLink(entry) { + if (entry == undefined) return false; + const unsafeKeywords = Config.options.workSafety.triggerCondition.linkKeywords; + return StringUtils.stringListContainsSubstring(entry.toLowerCase(), unsafeKeywords); + } + + Timer { + id: nonAppResultsTimer + interval: Config.options.search.nonAppResultDelay + onTriggered: { + let expr = root.query; + if (expr.startsWith(Config.options.search.prefix.math)) { + expr = expr.slice(Config.options.search.prefix.math.length); + } + mathProc.calculateExpression(expr); + } + } + + Process { + id: mathProc + property list baseCommand: ["qalc", "-t"] + function calculateExpression(expression) { + mathProc.running = false; + mathProc.command = baseCommand.concat(expression); + mathProc.running = true; + } + stdout: SplitParser { + onRead: data => { + root.mathResult = data; + } + } + } + + property list results: { + // Search results are handled here + ////////////////// Skip? ////////////////// + if (root.query == "") + return []; + + ///////////// Special cases /////////////// + if (root.query.startsWith(Config.options.search.prefix.clipboard)) { + // Clipboard + const searchString = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.clipboard); + return Cliphist.fuzzyQuery(searchString).map((entry, index, array) => { + const mightBlurImage = Cliphist.entryIsImage(entry) && root.clipboardWorkSafetyActive; + let shouldBlurImage = mightBlurImage; + if (mightBlurImage) { + shouldBlurImage = shouldBlurImage && (root.containsUnsafeLink(array[index - 1]) || root.containsUnsafeLink(array[index + 1])); + } + const type = `#${entry.match(/^\s*(\S+)/)?.[1] || ""}`; + return { + key: type, + cliphistRawString: entry, + name: StringUtils.cleanCliphistEntry(entry), + clickActionName: "", + type: type, + execute: () => { + Cliphist.copy(entry); + }, + actions: [ + { + name: "Copy", + materialIcon: "content_copy", + execute: () => { + Cliphist.copy(entry); + } + }, + { + name: "Delete", + materialIcon: "delete", + execute: () => { + Cliphist.deleteEntry(entry); + } + } + ], + blurImage: shouldBlurImage, + blurImageText: Translation.tr("Work safety") + }; + }).filter(Boolean); + } else if (root.query.startsWith(Config.options.search.prefix.emojis)) { + // Clipboard + const searchString = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.emojis); + return Emojis.fuzzyQuery(searchString).map(entry => { + const emoji = entry.match(/^\s*(\S+)/)?.[1] || ""; + return { + key: emoji, + cliphistRawString: entry, + bigText: emoji, + name: entry.replace(/^\s*\S+\s+/, ""), + clickActionName: "", + type: "Emoji", + execute: () => { + Quickshell.clipboardText = entry.match(/^\s*(\S+)/)?.[1]; + } + }; + }).filter(Boolean); + } + + ////////////////// Init /////////////////// + nonAppResultsTimer.restart(); + const mathResultObject = { + key: `Math result: ${root.mathResult}`, + name: root.mathResult, + clickActionName: Translation.tr("Copy"), + type: Translation.tr("Math result"), + fontType: "monospace", + materialSymbol: 'calculate', + execute: () => { + Quickshell.clipboardText = root.mathResult; + } + }; + const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.query, Config.options.search.prefix.app)).map(entry => { + entry.clickActionName = Translation.tr("Launch"); + entry.type = Translation.tr("App"); + entry.key = entry.execute; + return entry; + }); + const commandResultObject = { + key: `cmd ${root.query}`, + name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.shellCommand).replace("file://", ""), + clickActionName: Translation.tr("Run"), + type: Translation.tr("Run command"), + fontType: "monospace", + materialSymbol: 'terminal', + execute: () => { + let cleanedCommand = root.query.replace("file://", ""); + cleanedCommand = StringUtils.cleanPrefix(cleanedCommand, Config.options.search.prefix.shellCommand); + if (cleanedCommand.startsWith(Config.options.search.prefix.shellCommand)) { + cleanedCommand = cleanedCommand.slice(Config.options.search.prefix.shellCommand.length); + } + Quickshell.execDetached(["bash", "-c", searchingText.startsWith('sudo') ? `${Config.options.apps.terminal} fish -C '${cleanedCommand}'` : cleanedCommand]); + } + }; + const webSearchResultObject = { + key: `website ${root.query}`, + name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.webSearch), + clickActionName: Translation.tr("Search"), + type: Translation.tr("Search the web"), + materialSymbol: 'travel_explore', + execute: () => { + let query = StringUtils.cleanPrefix(root.query, Config.options.search.prefix.webSearch); + let url = Config.options.search.engineBaseUrl + query; + for (let site of Config.options.search.excludedSites) { + url += ` -site:${site}`; + } + Qt.openUrlExternally(url); + } + }; + const launcherActionObjects = root.searchActions.map(action => { + const actionString = `${Config.options.search.prefix.action}${action.action}`; + if (actionString.startsWith(root.query) || root.query.startsWith(actionString)) { + return { + key: `Action ${actionString}`, + name: root.query.startsWith(actionString) ? root.query : actionString, + clickActionName: Translation.tr("Run"), + type: Translation.tr("Action"), + materialSymbol: 'settings_suggest', + execute: () => { + action.execute(root.query.split(" ").slice(1).join(" ")); + } + }; + } + return null; + }).filter(Boolean); + + //////// Prioritized by prefix ///////// + let result = []; + const startsWithNumber = /^\d/.test(root.query); + const startsWithMathPrefix = root.query.startsWith(Config.options.search.prefix.math); + const startsWithShellCommandPrefix = root.query.startsWith(Config.options.search.prefix.shellCommand); + const startsWithWebSearchPrefix = root.query.startsWith(Config.options.search.prefix.webSearch); + if (startsWithNumber || startsWithMathPrefix) { + result.push(mathResultObject); + } else if (startsWithShellCommandPrefix) { + result.push(commandResultObject); + } else if (startsWithWebSearchPrefix) { + result.push(webSearchResultObject); + } + + //////////////// Apps ////////////////// + result = result.concat(appResultObjects); + + ////////// Launcher actions //////////// + result = result.concat(launcherActionObjects); + + /// Math result, command, web search /// + if (Config.options.search.prefix.showDefaultActionsWithoutPrefix) { + if (!startsWithShellCommandPrefix) + result.push(commandResultObject); + if (!startsWithNumber && !startsWithMathPrefix) + result.push(mathResultObject); + if (!startsWithWebSearchPrefix) + result.push(webSearchResultObject); + } + + return result; + } +} From f08bbc0d67b7d52614b73da3bcf13553d783f690 Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Tue, 2 Dec 2025 21:28:18 +0800 Subject: [PATCH 13/16] Update env.conf --- dots/.config/hypr/hyprland/env.conf | 8 -------- 1 file changed, 8 deletions(-) diff --git a/dots/.config/hypr/hyprland/env.conf b/dots/.config/hypr/hyprland/env.conf index bd45f9f7e..acc363cc6 100644 --- a/dots/.config/hypr/hyprland/env.conf +++ b/dots/.config/hypr/hyprland/env.conf @@ -1,11 +1,3 @@ -# ######### Input method ########## -# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland -#env = QT_IM_MODULE, fcitx -#env = XMODIFIERS, @im=fcitx -#env = SDL_IM_MODULE, fcitx -#env = GLFW_IM_MODULE, ibus -#env = INPUT_METHOD, fcitx - # ############ Wayland ############# env = ELECTRON_OZONE_PLATFORM_HINT,auto From 1d40360cf241d3925ae6c9e0581218b9e500beb2 Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Tue, 2 Dec 2025 21:28:41 +0800 Subject: [PATCH 14/16] Update env.conf --- dots/.config/hypr/custom/env.conf | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/dots/.config/hypr/custom/env.conf b/dots/.config/hypr/custom/env.conf index fcd59ec86..3215877be 100644 --- a/dots/.config/hypr/custom/env.conf +++ b/dots/.config/hypr/custom/env.conf @@ -1,2 +1,10 @@ # You can put extra environment variables here # https://wiki.hyprland.org/Configuring/Environment-variables/ + +# ######### Input method ########## +# See https://fcitx-im.org/wiki/Using_Fcitx_5_on_Wayland +#env = QT_IM_MODULE, fcitx +#env = XMODIFIERS, @im=fcitx +#env = SDL_IM_MODULE, fcitx +#env = GLFW_IM_MODULE, ibus +#env = INPUT_METHOD, fcitx From cce06cc2f0e30df1e4749e45e33a7145cbb0bd1d Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Tue, 2 Dec 2025 21:29:11 +0800 Subject: [PATCH 15/16] Update execs.conf --- dots/.config/hypr/hyprland/execs.conf | 3 --- 1 file changed, 3 deletions(-) diff --git a/dots/.config/hypr/hyprland/execs.conf b/dots/.config/hypr/hyprland/execs.conf index bb5dd7225..2cad1308e 100644 --- a/dots/.config/hypr/hyprland/execs.conf +++ b/dots/.config/hypr/hyprland/execs.conf @@ -3,9 +3,6 @@ exec-once = ~/.config/hypr/hyprland/scripts/start_geoclue_agent.sh exec-once = qs -c $qsConfig & exec-once = ~/.config/hypr/custom/scripts/__restore_video_wallpaper.sh -# Input method -# exec-once = fcitx5 - # Core components (authentication, lock screen, notification daemon) exec-once = gnome-keyring-daemon --start --components=secrets exec-once = hypridle From 90f9467871ec932559831dd8dcd32935abc301b2 Mon Sep 17 00:00:00 2001 From: LIghtJUNction Date: Tue, 2 Dec 2025 21:29:37 +0800 Subject: [PATCH 16/16] Update execs.conf --- dots/.config/hypr/custom/execs.conf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dots/.config/hypr/custom/execs.conf b/dots/.config/hypr/custom/execs.conf index cae4ef6c5..66bb2b8b5 100644 --- a/dots/.config/hypr/custom/execs.conf +++ b/dots/.config/hypr/custom/execs.conf @@ -1,2 +1,6 @@ # You can make apps auto-start here # Relevant Hyprland wiki section: https://wiki.hyprland.org/Configuring/Keywords/#executing + +# Input method +# exec-once = fcitx5 +