diff --git a/dots/.config/hypr/custom/env.conf b/dots/.config/hypr/custom/env.conf index 3215877be..4e59a32c2 100644 --- a/dots/.config/hypr/custom/env.conf +++ b/dots/.config/hypr/custom/env.conf @@ -8,3 +8,15 @@ #env = SDL_IM_MODULE, fcitx #env = GLFW_IM_MODULE, ibus #env = INPUT_METHOD, fcitx + +# ######## Wayland ######### +# Tearing +# env = WLR_DRM_NO_ATOMIC, 1 +# ? +# env = WLR_NO_HARDWARE_CURSORS, 1 + +# ######## EDITOR ######### +#https://wiki.archlinux.org/title/Category:Text_editors +# for example: vi nano nvim ... + +#env = EDITOR, vim diff --git a/dots/.config/hypr/custom/general.conf b/dots/.config/hypr/custom/general.conf index ded706ae7..aa3fd4f83 100644 --- a/dots/.config/hypr/custom/general.conf +++ b/dots/.config/hypr/custom/general.conf @@ -1,2 +1,6 @@ # Put general config stuff here -# Here's a list of every variable: https://wiki.hyprland.org/Configuring/Variables/ \ No newline at end of file +# Here's a list of every variable: https://wiki.hyprland.org/Configuring/Variables/ + +# monitor=,addreserved, 0, 0, 0, 0 # Custom reserved area + +# HDMI port: mirror display. To see device name, use `hyprctl monitors` diff --git a/dots/.config/hypr/custom/keybinds.conf b/dots/.config/hypr/custom/keybinds.conf index f2a568394..8885a2175 100644 --- a/dots/.config/hypr/custom/keybinds.conf +++ b/dots/.config/hypr/custom/keybinds.conf @@ -4,6 +4,19 @@ bind = Ctrl+Super, Slash, exec, xdg-open ~/.config/illogical-impulse/config.json # Edit shell config bind = Ctrl+Super+Alt, Slash, exec, xdg-open ~/.config/hypr/custom/keybinds.conf # Edit extra keybinds +##! Apps +# bind = Super, Return, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "${TERMINAL}" "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # Terminal +# bind = Super, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "${TERMINAL}" "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] (terminal) (alt) +# bind = Ctrl+Alt, T, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "${TERMINAL}" "kitty -1" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm" # [hidden] (terminal) (for Ubuntu people) +# bind = Super, E, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "dolphin" "nautilus" "nemo" "thunar" "${TERMINAL}" "kitty -1 fish -c yazi" # File manager +# bind = Super, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "google-chrome-stable" "zen-browser" "firefox" "brave" "chromium" "microsoft-edge-stable" "opera" "librewolf" # Browser +# bind = Super, C, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "code" "codium" "cursor" "zed" "zedit" "zeditor" "kate" "gnome-text-editor" "emacs" "command -v nvim && kitty -1 nvim" "command -v micro && kitty -1 micro" # Code editor +# bind = Ctrl+Super+Shift+Alt, W, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "wps" "onlyoffice-desktopeditors" "libreoffice" # Office software +# bind = Super, X, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "kate" "gnome-text-editor" "emacs" # Text editor +# bind = Ctrl+Super, V, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "pavucontrol-qt" "pavucontrol" # Volume mixer +# bind = Super, I, exec, XDG_CURRENT_DESKTOP=gnome ~/.config/hypr/hyprland/scripts/launch_first_available.sh "qs -p ~/.config/quickshell/$qsConfig/settings.qml" "systemsettings" "gnome-control-center" "better-control" # Settings app +# bind = Ctrl+Shift, Escape, exec, ~/.config/hypr/hyprland/scripts/launch_first_available.sh "gnome-system-monitor" "plasma-systemmonitor --page-name Processes" "command -v btop && kitty -1 fish -c btop" # Task manager + # Add stuff here # Use #! to add an extra column on the cheatsheet # Use ##! to add a section in that column diff --git a/dots/.config/hypr/custom/rules.conf b/dots/.config/hypr/custom/rules.conf index 159de0915..b253bc8d1 100644 --- a/dots/.config/hypr/custom/rules.conf +++ b/dots/.config/hypr/custom/rules.conf @@ -1,3 +1,11 @@ # You can put custom rules here # Window/layer rules: https://wiki.hyprland.org/Configuring/Window-Rules/ # Workspace rules: https://wiki.hyprland.org/Configuring/Workspace-Rules/ + +# ######## Window rules ######## + +# Uncomment to apply global transparency to all windows: +# windowrulev2 = opacity 0.89 override 0.89 override, class:.* + +# Disable blur for all xwayland apps +# windowrulev2 = noblur, xwayland:1 \ No newline at end of file diff --git a/dots/.config/hypr/hyprland/env.conf b/dots/.config/hypr/hyprland/env.conf index acc363cc6..affd1ca82 100644 --- a/dots/.config/hypr/hyprland/env.conf +++ b/dots/.config/hypr/hyprland/env.conf @@ -9,12 +9,6 @@ env = QT_QPA_PLATFORM, wayland env = QT_QPA_PLATFORMTHEME, kde env = XDG_MENU_PREFIX, plasma- -# ######## Wayland ######### -# Tearing -# env = WLR_DRM_NO_ATOMIC, 1 -# ? -# env = WLR_NO_HARDWARE_CURSORS, 1 - # ######## Virtual envrionment ######### env = ILLOGICAL_IMPULSE_VIRTUAL_ENV, ~/.local/state/quickshell/.venv diff --git a/dots/.config/hypr/hyprland/general.conf b/dots/.config/hypr/hyprland/general.conf index c4c54bc28..77580552d 100644 --- a/dots/.config/hypr/hyprland/general.conf +++ b/dots/.config/hypr/hyprland/general.conf @@ -1,9 +1,5 @@ # MONITOR CONFIG monitor=,preferred,auto,1 -# monitor=,addreserved, 0, 0, 0, 0 # Custom reserved area - -# HDMI port: mirror display. To see device name, use `hyprctl monitors` -# monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 gesture = 3, swipe, move, gesture = 3, pinch, float diff --git a/dots/.config/hypr/hyprland/rules.conf b/dots/.config/hypr/hyprland/rules.conf index cfb1e3f7b..a6e4d4e48 100644 --- a/dots/.config/hypr/hyprland/rules.conf +++ b/dots/.config/hypr/hyprland/rules.conf @@ -1,12 +1,8 @@ # ######## Window rules ######## -# Uncomment to apply global transparency to all windows: -# windowrulev2 = opacity 0.89 override 0.89 override, class:.* - # Disable blur for xwayland context menus windowrulev2 = noblur,class:^()$,title:^()$ -# Disable blur for all xwayland apps -# windowrulev2 = noblur, xwayland:1 + # Disable blur for every window windowrulev2 = noblur, class:.* diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/app-generic-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/app-generic-filled.svg new file mode 100644 index 000000000..87c7b6c41 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/app-generic-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/app-generic.svg b/dots/.config/quickshell/ii/assets/icons/fluent/app-generic.svg new file mode 100644 index 000000000..cd0c7b516 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/app-generic.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left-filled.svg new file mode 100644 index 000000000..f183cc835 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left.svg b/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left.svg new file mode 100644 index 000000000..c9ffd3eda --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/arrow-enter-left.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/calculator-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/calculator-filled.svg new file mode 100644 index 000000000..92ad06215 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/calculator-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/calculator.svg b/dots/.config/quickshell/ii/assets/icons/fluent/calculator.svg new file mode 100644 index 000000000..0dc9d3056 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/calculator.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/desktop-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/desktop-filled.svg new file mode 100644 index 000000000..d09661aec --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/desktop-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/desktop.svg b/dots/.config/quickshell/ii/assets/icons/fluent/desktop.svg new file mode 100644 index 000000000..979d35cc3 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/desktop.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/globe-search-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/globe-search-filled.svg new file mode 100644 index 000000000..933c6282d --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/globe-search-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/globe-search.svg b/dots/.config/quickshell/ii/assets/icons/fluent/globe-search.svg new file mode 100644 index 000000000..caa2c94ff --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/globe-search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/image-copy-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/image-copy-filled.svg new file mode 100644 index 000000000..f01cd9872 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/image-copy-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/image-copy.svg b/dots/.config/quickshell/ii/assets/icons/fluent/image-copy.svg new file mode 100644 index 000000000..a40940693 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/image-copy.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/image-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/image-filled.svg new file mode 100644 index 000000000..d35954106 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/image-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/image.svg b/dots/.config/quickshell/ii/assets/icons/fluent/image.svg new file mode 100644 index 000000000..379a1cd14 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/image.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/library-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/library-filled.svg new file mode 100644 index 000000000..7afac3d5e --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/library-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/library.svg b/dots/.config/quickshell/ii/assets/icons/fluent/library.svg new file mode 100644 index 000000000..79432ebdd --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/library.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/news-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/news-filled.svg new file mode 100644 index 000000000..1d07cf802 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/news-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/news.svg b/dots/.config/quickshell/ii/assets/icons/fluent/news.svg new file mode 100644 index 000000000..9e0c3a2fe --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/news.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/open-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/open-filled.svg new file mode 100644 index 000000000..95ae58d39 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/open-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/open.svg b/dots/.config/quickshell/ii/assets/icons/fluent/open.svg new file mode 100644 index 000000000..561ed5ec2 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/open.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people-filled.svg new file mode 100644 index 000000000..96e98b863 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people-settings-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people-settings-filled.svg new file mode 100644 index 000000000..0bcd7d12d --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people-settings-filled.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people-settings.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people-settings.svg new file mode 100644 index 000000000..8ff1df32a --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people-settings.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people-team-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people-team-filled.svg new file mode 100644 index 000000000..84364ec4e --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people-team-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people-team.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people-team.svg new file mode 100644 index 000000000..8507e971c --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people-team.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/people.svg b/dots/.config/quickshell/ii/assets/icons/fluent/people.svg new file mode 100644 index 000000000..967192214 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/people.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/record-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/record-filled.svg new file mode 100644 index 000000000..164d37e87 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/record-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/record.svg b/dots/.config/quickshell/ii/assets/icons/fluent/record.svg new file mode 100644 index 000000000..31e957588 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/record.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/server-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/server-filled.svg new file mode 100644 index 000000000..2b0869653 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/server-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/server.svg b/dots/.config/quickshell/ii/assets/icons/fluent/server.svg new file mode 100644 index 000000000..1b876a172 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/server.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft-filled.svg new file mode 100644 index 000000000..6673448f3 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft.svg b/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft.svg new file mode 100644 index 000000000..affc6cc6e --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/store-microsoft.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wand-filled.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wand-filled.svg new file mode 100644 index 000000000..fffb70e7f --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wand-filled.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wand.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wand.svg new file mode 100644 index 000000000..a5033c274 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wand.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/common/models/LauncherSearchResult.qml b/dots/.config/quickshell/ii/modules/common/models/LauncherSearchResult.qml index 15beef12e..c47fc4f39 100644 --- a/dots/.config/quickshell/ii/modules/common/models/LauncherSearchResult.qml +++ b/dots/.config/quickshell/ii/modules/common/models/LauncherSearchResult.qml @@ -19,11 +19,14 @@ QtObject { } property var actions: [] - // Stuff needed for DesktopEntry objects + // Stuff needed for DesktopEntry + property string id: "" property bool shown: true property string comment: "" property bool runInTerminal: false property string genericName: "" property list keywords: [] + // Extra stuff to allow for more flexibility + property string category: type } diff --git a/dots/.config/quickshell/ii/modules/common/widgets/StyledScrollBar.qml b/dots/.config/quickshell/ii/modules/common/widgets/StyledScrollBar.qml index 7b677c426..f37203250 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/StyledScrollBar.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/StyledScrollBar.qml @@ -9,6 +9,7 @@ ScrollBar { policy: ScrollBar.AsNeeded topPadding: Appearance.rounding.normal bottomPadding: Appearance.rounding.normal + active: hovered || pressed contentItem: Rectangle { implicitWidth: 4 diff --git a/dots/.config/quickshell/ii/modules/ii/lock/Lock.qml b/dots/.config/quickshell/ii/modules/ii/lock/Lock.qml index e942f4fda..3d6506c54 100644 --- a/dots/.config/quickshell/ii/modules/ii/lock/Lock.qml +++ b/dots/.config/quickshell/ii/modules/ii/lock/Lock.qml @@ -72,7 +72,7 @@ Scope { } // Unlock the keyring if configured to do so - if (Config.options.lock.security.unlockKeyring) root.unlockKeyring(); + if (Config.options.lock.security.unlockKeyring) root.unlockKeyring(); // Async // Unlock the screen before exiting, or the compositor will display a // fallback lock you can't interact with. @@ -83,6 +83,12 @@ Scope { // Reset lockContext.reset(); + + // Post-unlock actions + if (lockContext.alsoInhibitIdle) { + lockContext.alsoInhibitIdle = false; + Idle.toggleInhibit(true); + } } } diff --git a/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml b/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml index b242cdc05..e6454b476 100644 --- a/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml +++ b/dots/.config/quickshell/ii/modules/ii/lock/LockContext.qml @@ -21,6 +21,7 @@ Scope { property bool showFailure: false property bool fingerprintsConfigured: false property var targetAction: LockContext.ActionEnum.Unlock + property bool alsoInhibitIdle: false function resetTargetAction() { root.targetAction = LockContext.ActionEnum.Unlock; @@ -58,7 +59,8 @@ Scope { passwordClearTimer.restart(); } - function tryUnlock() { + function tryUnlock(alsoInhibitIdle = false) { + root.alsoInhibitIdle = alsoInhibitIdle; root.unlockInProgress = true; pam.start(); } diff --git a/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml b/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml index da3e17627..e44eecacb 100644 --- a/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml +++ b/dots/.config/quickshell/ii/modules/ii/lock/LockSurface.qml @@ -59,10 +59,20 @@ MouseArea { } // Key presses + property bool ctrlHeld: false Keys.onPressed: event => { root.context.resetClearTimer(); + if (event.key === Qt.Key_Control) { + root.ctrlHeld = true; + } if (event.key === Qt.Key_Escape) { // Esc to clear root.context.currentText = ""; + } + forceFieldFocus(); + } + Keys.onReleased: event => { + if (event.key === Qt.Key_Control) { + root.ctrlHeld = false; } forceFieldFocus(); } @@ -133,7 +143,9 @@ MouseArea { // Synchronizing (across monitors) and unlocking onTextChanged: root.context.currentText = this.text - onAccepted: root.context.tryUnlock() + onAccepted: { + root.context.tryUnlock(ctrlHeld); + } Connections { target: root.context function onCurrentTextChanged() { @@ -202,7 +214,7 @@ MouseArea { iconSize: 24 text: { if (root.context.targetAction === LockContext.ActionEnum.Unlock) { - return "arrow_right_alt"; + return root.ctrlHeld ? "emoji_food_beverage" : "arrow_right_alt"; } else if (root.context.targetAction === LockContext.ActionEnum.Poweroff) { return "power_settings_new"; } else if (root.context.targetAction === LockContext.ActionEnum.Reboot) { diff --git a/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml b/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml index a52471ba6..8f484591b 100644 --- a/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml +++ b/dots/.config/quickshell/ii/modules/ii/regionSelector/RegionSelection.qml @@ -26,7 +26,7 @@ PanelWindow { bottom: true } - // TODO: Ask: sidebar AI; Ocr: tesseract + // TODO: Ask: sidebar AI enum SnipAction { Copy, Edit, Search, CharRecognition, Record, RecordWithSound } enum SelectionMode { RectCorners, Circle } property var action: RegionSelection.SnipAction.Copy diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml index f7c2dc9f8..dab92df5f 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml @@ -30,6 +30,12 @@ ColumnLayout { required property var modelData node: modelData } + PagePlaceholder { + icon: "widgets" + title: Translation.tr("No applications") + shown: !root.hasApps + shape: MaterialShape.Shape.Cookie7Sided + } } StyledComboBox { diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml index b9cbc00bd..802add786 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml @@ -17,8 +17,8 @@ Singleton { property string iconsPath: `${Directories.assetsPath}/icons/fluent` property bool dark: Appearance.m3colors.darkmode - property real backgroundTransparency: 0.13 - property real panelBackgroundTransparency: 0.12 + property real backgroundTransparency: 0.16 + property real panelBackgroundTransparency: 0.14 property real panelLayerTransparency: root.dark ? 0.9 : 0.7 property real contentTransparency: root.dark ? 0.87 : 0.5 function applyBackgroundTransparency(col) { @@ -152,6 +152,7 @@ Singleton { property real normal: 11 property real large: 13 property real larger: 15 + property real xlarger: 17 } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml index 7fe121165..b804aa3d9 100644 --- a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml @@ -48,7 +48,7 @@ Singleton { } property string batteryLevelIcon: { - const discreteLevel = Math.ceil(Battery.percentage * 10) + const discreteLevel = Math.ceil(Battery.percentage * 10); return `battery-${discreteLevel > 9 ? "full" : discreteLevel}`; } @@ -107,7 +107,8 @@ Singleton { function audioAppIcon(node) { let icon; icon = AppSearch.guessIcon(node?.properties["application.icon-name"] ?? ""); - if (AppSearch.iconExists(icon)) return icon; + if (AppSearch.iconExists(icon)) + return icon; icon = AppSearch.guessIcon(node?.properties["node.name"] ?? ""); return icon; } @@ -127,4 +128,60 @@ Singleton { return "bluetooth"; } + function fluentFromMaterial(icon) { + switch (icon) { + case "calculate": + return "calculator"; + case "keyboard_return": + return "arrow-enter-left"; + case "open_in_new": + return "open"; + case "settings_suggest": + return "wand"; + case "terminal": + return "app-generic"; + case "travel_explore": + return "globe-search"; + case "keep": + return "pin"; + case "keep_off": + return "pin-off"; + default: + return "apps"; + } + } + + function guessIconForName(name) { + const lowerName = name.toLowerCase(); + if (lowerName.includes("app") || lowerName.includes("desktop")) + return "apps"; + if (lowerName.includes("news")) + return "news"; + if (lowerName.includes("new") || lowerName.includes("create") || lowerName.includes("add")) + return "add"; + if (lowerName.includes("open")) + return "open"; + if (lowerName.includes("friends") || lowerName.includes("contact") || lowerName.includes("family")) + return "people"; + if (lowerName.includes("community")) + return "people-team"; + if (lowerName.includes("library")) + return "library"; + if (lowerName.includes("setting")) + return "settings"; + if (lowerName.includes("gallery")) + return "image-copy"; + if (lowerName.includes("server")) + return "server"; + if (lowerName.includes("picture") || lowerName.includes("photo") || lowerName.includes("image")) + return "image"; + if (lowerName.includes("store") || lowerName.includes("shop")) + return "store-microsoft"; + if (lowerName.includes("record") || lowerName.includes("capture")) + return "record"; + if (lowerName.includes("screen") || lowerName.includes("display") || lowerName.includes("monitor") || lowerName.includes("desktop")) + return "desktop"; + + return "apps"; + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml new file mode 100644 index 000000000..bc567762a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WListView.qml @@ -0,0 +1,10 @@ +import qs.modules.common +import qs.modules.common.widgets +import QtQuick +import QtQuick.Controls + +ListView { + id: root + + ScrollBar.vertical: WScrollBar {} +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WScrollBar.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WScrollBar.qml new file mode 100644 index 000000000..bdc962806 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WScrollBar.qml @@ -0,0 +1,25 @@ +import QtQuick +import QtQuick.Controls +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions + +ScrollBar { + id: root + + policy: ScrollBar.AsNeeded + active: hovered || pressed + property color color: Looks.colors.controlBg + + contentItem: Rectangle { + implicitWidth: root.active ? 4 : 2 + implicitHeight: root.visualSize + radius: 9999 + color: root.color + + opacity: root.policy === ScrollBar.AlwaysOn || (root.active && root.size < 1.0) ? 0.5 : 0 + Behavior on opacity { + animation: Looks.transition.opacity.createObject(this) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml index ce5652329..d38bc8d98 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchBar.qml @@ -15,10 +15,16 @@ FooterRectangle { property real horizontalPadding: 32 property real verticalPadding: 16 property bool searching: text.length > 0 + property alias searchInput: searchInput property alias text: searchInput.text implicitHeight: outline.implicitHeight + verticalPadding * 2 - Component.onCompleted: searchInput.forceActiveFocus() + signal accepted() + + Component.onCompleted: forceFocus() + function forceFocus() { + searchInput.forceActiveFocus(); + } focus: true color: searching ? Looks.colors.bgPanelBody : Looks.colors.bgPanelFooter @@ -81,6 +87,10 @@ FooterRectangle { visible: searchInput.text.length === 0 font.pixelSize: Looks.font.pixelSize.large } + + onAccepted: { + root.accepted(); + } } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchEntryIcon.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchEntryIcon.qml new file mode 100644 index 000000000..5f94870b7 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchEntryIcon.qml @@ -0,0 +1,48 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs +import qs.services +import qs.modules.common +import qs.modules.common.models +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +Item { + id: root + required property LauncherSearchResult entry + property int iconSize: 24 + implicitWidth: Math.max(iconSize, textIconLoader.implicitWidth) + implicitHeight: iconSize + Loader { + anchors.centerIn: parent + active: root.entry.iconType === LauncherSearchResult.IconType.System && root.entry.iconName !== "" + sourceComponent: WAppIcon { + implicitSize: root.iconSize + iconName: root.entry.iconName + tryCustomIcon: false + animated: false + } + } + Loader { + id: textIconLoader + anchors.centerIn: parent + active: root.entry.iconType === LauncherSearchResult.IconType.Text + sourceComponent: WText { + text: root.entry.iconName + font.pixelSize: root.iconSize + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + Loader { + anchors.centerIn: parent + active: root.entry.iconType === LauncherSearchResult.IconType.Material || root.entry.iconType === LauncherSearchResult.IconType.None || root.entry.iconName === "" + sourceComponent: FluentIcon { + icon: root.entry.iconName ? WIcons.fluentFromMaterial(root.entry.iconName) : WIcons.guessIconForName(root.entry.name) + implicitSize: root.iconSize + animated: false + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml index a294950fd..b6f4a4e94 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchPageContent.qml @@ -12,7 +12,9 @@ import qs.modules.waffle.looks BodyRectangle { id: root + property alias context: searchResults.context property string searchText: LauncherSearch.query + property alias currentIndex: searchResults.currentIndex ColumnLayout { anchors { @@ -24,11 +26,13 @@ BodyRectangle { spacing: 12 TagStrip { + context: root.context Layout.fillWidth: true Layout.fillHeight: false } SearchResults { + id: searchResults Layout.fillWidth: true Layout.fillHeight: true } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml index 5f3d93411..a9e83929e 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/SearchResults.qml @@ -1,19 +1,44 @@ +pragma ComponentBehavior: Bound +import qs +import qs.services +import qs.modules.common import qs.modules.waffle.looks import qs.modules.common.functions -import qs.modules.common -import qs.services -import qs +import qs.modules.common.models import Quickshell import QtQuick.Layouts import QtQuick.Controls import QtQuick -pragma ComponentBehavior: Bound RowLayout { id: root + property int maxResultsPerCategory: 4 + property StartMenuContext context + property int currentIndex: context.currentIndex + onCurrentIndexChanged: { + forceCurrentIndex(currentIndex); + } function focusFirstItem() { - resultList.currentIndex = 0; + forceCurrentIndex(0); + } + function forceCurrentIndex(index) { + context.currentIndex = index; + // Somehow this hack is needed + if (index === 0) { + resultList.incrementCurrentIndex(); + resultList.decrementCurrentIndex(); + } else { + resultList.decrementCurrentIndex(); + resultList.incrementCurrentIndex(); + } + } + + Connections { + target: context + function onAccepted() { + resultList.currentItem?.execute(); + } } ResultList { @@ -25,23 +50,74 @@ RowLayout { Layout.preferredWidth: 386 Layout.leftMargin: 1 Layout.rightMargin: 1 + entry: resultList.model[resultList.currentIndex] ?? searchResultComp.createObject() } - component ResultList: ListView { + component ResultList: WListView { + id: resultListView section { criteria: ViewSection.FullString - property: "type" + property: "category" // This is "type" with tweaks to make it match more closely + labelPositioning: ViewSection.InlineLabels + delegate: Item { + id: sectionButton + required property string section + implicitHeight: sectionChoiceButton.implicitHeight + resultListView.spacing + width: ListView.view?.width + WChoiceButton { + id: sectionChoiceButton + anchors { + left: parent.left + right: parent.right + top: parent.top + } + implicitHeight: 38 + contentItem: WText { + text: sectionButton.section + font.pixelSize: Looks.font.pixelSize.large + font.weight: Looks.font.weight.strong + } + onClicked: { + root.context.selectCategory(sectionButton.section); + } + } + } } clip: true spacing: 4 - model: ScriptModel { - values: { - // TODO: categorize and have max per category - LauncherSearch.results.slice(0, 10) - } - onValuesChanged: { - root.focusFirstItem(); + currentIndex: root.currentIndex + + // We can't use a ScriptModel here because it would mess up sections + model: { + const allResults = LauncherSearch.results; + // Find categories + var categories = new Set(); + for (let i = 0; i < allResults.length; i++) { + categories.add(allResults[i].type); } + + // Collect max 4 per category + var categorizedResults = []; + categories.forEach(category => { + let count = 0; + for (let i = 0; i < allResults.length; i++) { + if (allResults[i].type === category) { + const entry = allResults[i]; + const tweakedEntry = searchResultComp.createObject(null, Object.assign({}, entry)); + tweakedEntry.category = categorizedResults.length === 0 ? Translation.tr("Best match") : entry.type + categorizedResults.push(tweakedEntry); // Section header + count++; + if (count >= root.maxResultsPerCategory) { + break; + } + } + } + }); + // print(JSON.stringify(categorizedResults, null, 2)); + return categorizedResults; + } + onModelChanged: { + root.focusFirstItem(); } delegate: WSearchResultButton { required property int index @@ -49,12 +125,120 @@ RowLayout { entry: modelData firstEntry: index === 0 width: ListView.view?.width + checked: resultListView.currentIndex === index + onRequestFocus: { + root.forceCurrentIndex(index); + } } } component ResultPreview: Rectangle { + id: resultPreview + + property LauncherSearchResult entry // LauncherSearchResult + Layout.fillHeight: true color: Looks.colors.bg1 radius: Looks.radius.large + + ColumnLayout { + anchors.fill: parent + anchors.margins: 22 + spacing: 13 + + ColumnLayout { + id: mainInfoColumn + Layout.alignment: Qt.AlignHCenter + SearchEntryIcon { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: 10 + Layout.bottomMargin: 12 + entry: resultPreview.entry + iconSize: 64 + } + WText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + wrapMode: Text.Wrap + maximumLineCount: 2 + text: resultPreview.entry?.name || "" + font.pixelSize: Looks.font.pixelSize.xlarger + } + WText { + Layout.alignment: Qt.AlignHCenter + text: resultPreview.entry?.type || "" + color: Looks.colors.accentUnfocused + font.pixelSize: Looks.font.pixelSize.normal + } + } + Rectangle { + id: resultSeparator + implicitHeight: 2 + Layout.topMargin: 16 + Layout.fillWidth: true + color: Looks.colors.bg2Hover + } + WListView { + id: actionsColumn + Layout.fillHeight: true + Layout.fillWidth: true + clip: true + spacing: 2 + model: { + const isAppEntry = resultPreview.entry.type === Translation.tr("App"); + const appId = isAppEntry ? resultPreview.entry.id : ""; + const pinned = isAppEntry ? (Config.options.dock.pinnedApps.includes(appId)) : false; + var result = [ + searchResultComp.createObject(null, { + name: resultPreview.entry.verb, + iconName: isAppEntry ? "open_in_new" : "keyboard_return", + iconType: LauncherSearchResult.IconType.Material, + execute: () => { + resultPreview.entry.execute(); + } + }), + ...(isAppEntry ? [ + searchResultComp.createObject(null, { + name: pinned ? Translation.tr("Unpin from taskbar") : Translation.tr("Pin to taskbar"), + iconName: pinned ? "keep_off" : "keep", + iconType: LauncherSearchResult.IconType.Material, + execute: () => { + TaskbarApps.togglePin(appId); + } + }) + ] : []) + ]; + result = result.concat(resultPreview.entry.actions); + return result; + } + delegate: WButton { + id: actionButton + required property var modelData + width: ListView.view?.width + icon.name: modelData.iconName + text: modelData.name + onClicked: modelData.execute(); + + contentItem: RowLayout { + spacing: 11 + SearchEntryIcon { + entry: actionButton.modelData + iconSize: 16 + } + WText { + Layout.fillWidth: true + horizontalAlignment: Text.AlignLeft + text: actionButton.text + } + } + } + } + } + } + + Component { + id: searchResultComp + LauncherSearchResult {} } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml index 09de017ee..2f76ca0ca 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContent.qml @@ -16,10 +16,72 @@ WBarAttachedPanelContent { property bool searching: false property string searchText: LauncherSearch.query + StartMenuContext { + id: context + } + + Keys.onPressed: event => { + // Prevent Esc and Backspace from registering + if (event.key === Qt.Key_Escape) + return; + + // Handle Backspace: focus and delete character if not focused + if (event.key === Qt.Key_Backspace) { + searchBar.forceFocus(); + if (event.modifiers & Qt.ControlModifier) { + // Delete word before cursor + let text = searchBar.text; + let pos = searchBar.searchInput.cursorPosition; + if (pos > 0) { + // Find the start of the previous word + let left = text.slice(0, pos); + let match = left.match(/(\s*\S+)\s*$/); + let deleteLen = match ? match[0].length : 1; + searchBar.text = text.slice(0, pos - deleteLen) + text.slice(pos); + searchBar.searchInput.cursorPosition = pos - deleteLen; + } + } else { + // Delete character before cursor if any + if (searchBar.searchInput.cursorPosition > 0) { + searchBar.text = searchBar.text.slice(0, searchBar.searchInput.cursorPosition - 1) + searchBar.text.slice(searchBar.searchInput.cursorPosition); + searchBar.searchInput.cursorPosition -= 1; + } + } + // Always move cursor to end after programmatic edit + searchBar.searchInput.cursorPosition = searchBar.text.length; + event.accepted = true; + // If already focused, let TextField handle it + return; + } + + // Only handle visible printable characters (ignore control chars, arrows, etc.) + if (event.text && event.text.length === 1 && event.key !== Qt.Key_Enter && event.key !== Qt.Key_Return && event.key !== Qt.Key_Delete && event.text.charCodeAt(0) >= 0x20) // ignore control chars like Backspace, Tab, etc. + { + if (!searchBar.searchInput.activeFocus) { + searchBar.forceFocus(); + // Insert the character at the cursor position + searchBar.text = searchBar.text.slice(0, searchBar.searchInput.cursorPosition) + event.text + searchBar.text.slice(searchBar.searchInput.cursorPosition); + searchBar.searchInput.cursorPosition += 1; + event.accepted = true; + context.setCurrentIndex(0); + } + } + + // Arrow keys for item navigation + if (event.key === Qt.Key_Down) { + let maxIndex = Math.max(0, LauncherSearch.results.length - 1); + context.setCurrentIndex(Math.min(context.currentIndex + 1, maxIndex)); + event.accepted = true; + } else if (event.key === Qt.Key_Up) { + context.setCurrentIndex(Math.max(context.currentIndex - 1, 0)); + event.accepted = true; + } + } + contentItem: WPane { contentItem: WPanelPageColumn { SearchBar { - focus: true + id: searchBar Layout.fillWidth: true implicitWidth: 832 // TODO: Make sizes naturally inferred horizontalPadding: root.searching ? 24 : 32 @@ -27,10 +89,14 @@ WBarAttachedPanelContent { Synchronizer on searching { property alias target: root.searching } + focus: true text: root.searchText onTextChanged: { LauncherSearch.query = text; } + onAccepted: { + context.accepted(); + } } Item { implicitHeight: root.searching ? 736 : 736 // TODO: Make sizes naturally inferred @@ -46,7 +112,9 @@ WBarAttachedPanelContent { Component { id: searchPageComp - SearchPageContent {} + SearchPageContent { + context: context + } } Component { diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContext.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContext.qml new file mode 100644 index 000000000..ff2289da0 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/StartMenuContext.qml @@ -0,0 +1,64 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import qs +import qs.modules.common +import qs.services + +Scope { + id: root + + signal accepted + + property int currentIndex: 0 + function setCurrentIndex(index) { + if (index == currentIndex) + return; + currentIndex = index; + } + + function selectCategory(category) { + for (let i = 0; i < root.categories.length; i++) { + const thisCategoryName = root.categories[i].name; + if (thisCategoryName.startsWith(category) || category.startsWith(thisCategoryName)) { + LauncherSearch.ensurePrefix(root.categories[i].prefix); + return; + } + } + } + property list categories: [ + { + name: Translation.tr("All"), + prefix: "" + }, + { + name: Translation.tr("Apps"), + prefix: Config.options.search.prefix.app + }, + { + name: Translation.tr("Actions"), + prefix: Config.options.search.prefix.action + }, + { + name: Translation.tr("Clipboard"), + prefix: Config.options.search.prefix.clipboard + }, + { + name: Translation.tr("Emojis"), + prefix: Config.options.search.prefix.emojis + }, + { + name: Translation.tr("Math"), + prefix: Config.options.search.prefix.math + }, + { + name: Translation.tr("Commands"), + prefix: Config.options.search.prefix.shellCommand + }, + { + name: Translation.tr("Web"), + prefix: Config.options.search.prefix.webSearch + }, + ] + +} diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml index 10448b5cd..a1deb0027 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/TagStrip.qml @@ -10,6 +10,9 @@ import qs.modules.common.functions import qs.modules.waffle.looks RowLayout { + id: root + property StartMenuContext context + WPanelIconButton { implicitWidth: 36 implicitHeight: 36 @@ -23,40 +26,8 @@ RowLayout { Layout.fillHeight: true orientation: Qt.Horizontal spacing: 4 - model: [ - { - name: Translation.tr("All"), - prefix: "" - }, - { - name: Translation.tr("Apps"), - prefix: Config.options.search.prefix.app - }, - { - name: Translation.tr("Actions"), - prefix: Config.options.search.prefix.action - }, - { - name: Translation.tr("Clipboard"), - prefix: Config.options.search.prefix.clipboard - }, - { - name: Translation.tr("Emojis"), - prefix: Config.options.search.prefix.emojis - }, - { - name: Translation.tr("Math"), - prefix: Config.options.search.prefix.math - }, - { - name: Translation.tr("Commands"), - prefix: Config.options.search.prefix.shellCommand - }, - { - name: Translation.tr("Web"), - prefix: Config.options.search.prefix.webSearch - }, - ] + model: root.context.categories + clip: true delegate: WBorderedButton { id: tagButton required property var modelData @@ -68,7 +39,7 @@ RowLayout { if (modelData.prefix != "") { return LauncherSearch.query.startsWith(modelData.prefix); } else { - return !tagListView.model.some(i => (i.prefix != "" && LauncherSearch.query.startsWith(i.prefix))) + return !tagListView.model.some(i => (i.prefix != "" && LauncherSearch.query.startsWith(i.prefix))); } } contentItem: Item { @@ -84,9 +55,27 @@ RowLayout { } } WPanelIconButton { + id: optionsButton implicitWidth: 36 implicitHeight: 36 iconSize: 24 iconName: "more-horizontal" + + onClicked: accountsMenu.open() + + WMenu { + id: accountsMenu + x: -accountsMenu.implicitWidth + optionsButton.implicitWidth + y: optionsButton.height + 10 + downDirection: true + Action { + icon.name: "people-settings" + text: Translation.tr("Manage accounts") + onTriggered: { + Quickshell.execDetached(["bash", "-c", Config.options.apps.manageUser]) + GlobalStates.searchOpen = false; + } + } + } } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml index 1aca104b0..b7fb1df14 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WSearchResultButton.qml @@ -11,51 +11,84 @@ import qs.modules.waffle.looks WChoiceButton { id: root - + required property LauncherSearchResult entry property bool firstEntry: false + signal requestFocus() + checked: focus animateChoiceHighlight: false implicitWidth: contentLayout.implicitWidth + leftPadding + rightPadding implicitHeight: contentLayout.implicitHeight + topPadding + bottomPadding onClicked: { - GlobalStates.searchOpen = false - root.entry.execute() - } - - contentItem: RowLayout { - id: contentLayout - spacing: 8 - - EntryIcon {} - EntryNameColumn { - Layout.fillWidth: true - Layout.alignment: Qt.AlignVCenter - } + execute(); } - component EntryIcon: Item { - implicitWidth: 24 - implicitHeight: 24 - Loader { - anchors.centerIn: parent - active: root.entry.iconType === LauncherSearchResult.IconType.System - sourceComponent: WAppIcon { - implicitSize: 24 - tryCustomIcon: false - iconName: root.entry.iconName + function execute() { + GlobalStates.searchOpen = false; + root.entry.execute(); + } + + horizontalPadding: 0 + verticalPadding: 0 + + contentItem: RowLayout { + id: contentLayout + spacing: 0 + + WButton { + id: launchButton + Layout.fillWidth: true + Layout.fillHeight: true + horizontalPadding: 10 + verticalPadding: 11 + implicitHeight: root.firstEntry ? 62 : 36 + implicitWidth: entryContentRow.implicitWidth + leftPadding + rightPadding + topRightRadius: 0 + bottomRightRadius: 0 + onClicked: root.click() + contentItem: Item { + RowLayout { + id: entryContentRow + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } + spacing: 8 + + SearchEntryIcon { + entry: root.entry + iconSize: 24 + } + EntryNameColumn { + Layout.fillWidth: true + Layout.alignment: Qt.AlignVCenter + } + } } } - Loader { - anchors.centerIn: parent - active: root.entry.iconType === LauncherSearchResult.IconType.Text - sourceComponent: WText { - text: root.entry.iconName - font.pixelSize: 24 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + Rectangle { + id: separator + opacity: (root.hovered && !root.checked) ? 1 : 0 + Layout.fillHeight: true + implicitWidth: 1 + color: ColorUtils.transparentize(Looks.colors.fg, 0.75) + } + WButton { + visible: !root.checked + Layout.fillHeight: true + implicitWidth: 47 + topLeftRadius: 0 + bottomLeftRadius: 0 + onClicked: root.requestFocus() + contentItem: Item { + FluentIcon { + anchors.centerIn: parent + icon: "chevron-right" + implicitSize: 14 + } } } } @@ -78,4 +111,11 @@ WChoiceButton { color: Looks.colors.accentUnfocused } } + + MouseArea { + anchors.fill: parent + // hoverEnabled: true + acceptedButtons: Qt.NoButton + cursorShape: Qt.PointingHandCursor + } } diff --git a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml index 9b59fb0c8..15ffc6f43 100644 --- a/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml +++ b/dots/.config/quickshell/ii/modules/waffle/startMenu/WaffleStartMenu.qml @@ -15,8 +15,10 @@ Scope { target: GlobalStates function onSearchOpenChanged() { - if (GlobalStates.searchOpen) + if (GlobalStates.searchOpen) { + LauncherSearch.query = ""; panelLoader.active = true; + } } } @@ -62,6 +64,7 @@ Scope { onClosed: { GlobalStates.searchOpen = false; panelLoader.active = false; + LauncherSearch.query = ""; } } } diff --git a/dots/.config/quickshell/ii/services/Audio.qml b/dots/.config/quickshell/ii/services/Audio.qml index 4b45701a9..29b0a2f68 100644 --- a/dots/.config/quickshell/ii/services/Audio.qml +++ b/dots/.config/quickshell/ii/services/Audio.qml @@ -18,6 +18,7 @@ Singleton { readonly property real hardMaxValue: 2.00 // People keep joking about setting volume to 5172% so... property string audioTheme: Config.options.sounds.theme property real value: sink?.audio.volume ?? 0 + function friendlyDeviceName(node) { return (node.nickname || node.description || Translation.tr("Unknown")); } @@ -105,9 +106,9 @@ Singleton { if (newVolume - lastVolume > maxAllowedIncrease) { sink.audio.volume = lastVolume; root.sinkProtectionTriggered(Translation.tr("Illegal increment")); - } else if (newVolume > maxAllowed || newVolume > root.hardMaxValue) { + } else if (Math.round(newVolume * 100) / 100 > maxAllowed || newVolume > root.hardMaxValue) { root.sinkProtectionTriggered(Translation.tr("Exceeded max allowed")); - sink.audio.volume = Math.min(lastVolume, maxAllowed); + sink.audio.volume = maxAllowed; } lastVolume = sink.audio.volume; } diff --git a/dots/.config/quickshell/ii/services/Idle.qml b/dots/.config/quickshell/ii/services/Idle.qml index ad938f3c3..a2b804772 100644 --- a/dots/.config/quickshell/ii/services/Idle.qml +++ b/dots/.config/quickshell/ii/services/Idle.qml @@ -1,8 +1,8 @@ +pragma Singleton import qs.modules.common import QtQuick import Quickshell import Quickshell.Wayland -pragma Singleton /** * A nice wrapper for date and time strings. @@ -17,21 +17,26 @@ Singleton { target: Persistent function onReadyChanged() { if (!Persistent.isNewHyprlandInstance) { - root.inhibit = Persistent.states.idle.inhibit + root.inhibit = Persistent.states.idle.inhibit; } else { - Persistent.states.idle.inhibit = root.inhibit + Persistent.states.idle.inhibit = root.inhibit; } } } - function toggleInhibit() { - root.inhibit = !root.inhibit - Persistent.states.idle.inhibit = root.inhibit + function toggleInhibit(active = null) { + if (active !== null) { + root.inhibit = active; + } else { + root.inhibit = !root.inhibit; + } + Persistent.states.idle.inhibit = root.inhibit; } IdleInhibitor { id: idleInhibitor - window: PanelWindow { // Inhibitor requires a "visible" surface + window: PanelWindow { + // Inhibitor requires a "visible" surface // Actually not lol implicitWidth: 0 implicitHeight: 0 @@ -46,6 +51,5 @@ Singleton { item: null } } - } - + } } diff --git a/dots/.config/quickshell/ii/services/LauncherSearch.qml b/dots/.config/quickshell/ii/services/LauncherSearch.qml index 89d9e0056..49de2158e 100644 --- a/dots/.config/quickshell/ii/services/LauncherSearch.qml +++ b/dots/.config/quickshell/ii/services/LauncherSearch.qml @@ -198,10 +198,11 @@ Singleton { const appResultObjects = AppSearch.fuzzyQuery(StringUtils.cleanPrefix(root.query, Config.options.search.prefix.app)).map(entry => { return resultComp.createObject(null, { type: Translation.tr("App"), + id: entry.id, name: entry.name, iconName: entry.icon, iconType: LauncherSearchResult.IconType.System, - verb: Translation.tr("Launch"), + verb: Translation.tr("Open"), execute: () => { if (!entry.runInTerminal) entry.execute(); @@ -233,7 +234,7 @@ Singleton { const commandResultObject = resultComp.createObject(null, { name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.shellCommand).replace("file://", ""), verb: Translation.tr("Run"), - type: Translation.tr("Run command"), + type: Translation.tr("Command"), fontType: LauncherSearchResult.FontType.Monospace, iconName: 'terminal', iconType: LauncherSearchResult.IconType.Material, @@ -249,7 +250,7 @@ Singleton { const webSearchResultObject = resultComp.createObject(null, { name: StringUtils.cleanPrefix(root.query, Config.options.search.prefix.webSearch), verb: Translation.tr("Search"), - type: Translation.tr("Search the web"), + type: Translation.tr("Web search"), iconName: 'travel_explore', iconType: LauncherSearchResult.IconType.Material, execute: () => { diff --git a/dots/.config/quickshell/ii/services/Privacy.qml b/dots/.config/quickshell/ii/services/Privacy.qml new file mode 100644 index 000000000..a14da7689 --- /dev/null +++ b/dots/.config/quickshell/ii/services/Privacy.qml @@ -0,0 +1,16 @@ +pragma Singleton +pragma ComponentBehavior: Bound +import qs.modules.common +import QtQuick +import Quickshell +import Quickshell.Services.Pipewire + +/** + * Screensharing and mic activity. + */ +Singleton { + id: root + + property bool screenSharing: Pipewire.linkGroups.values.filter(pwlg => pwlg.source.type === PwNodeType.VideoSource).map(pwlg => pwlg.target) + property bool micActive: Pipewire.linkGroups.values.filter(pwlg => pwlg.source.type === PwNodeType.AudioSource && pwlg.target.type === PwNodeType.AudioInStream).map(pwlg => pwlg.target) +} diff --git a/dots/.config/quickshell/ii/services/ResourceUsage.qml b/dots/.config/quickshell/ii/services/ResourceUsage.qml index df823adf7..c513b90ca 100644 --- a/dots/.config/quickshell/ii/services/ResourceUsage.qml +++ b/dots/.config/quickshell/ii/services/ResourceUsage.qml @@ -102,6 +102,10 @@ Singleton { Process { id: findCpuMaxFreqProc + environment: ({ + LANG: "C", + LC_ALL: "C" + }) command: ["bash", "-c", "lscpu | grep 'CPU max MHz' | awk '{print $4}'"] running: true stdout: StdioCollector { diff --git a/sdata/dist-arch/install-deps.sh b/sdata/dist-arch/install-deps.sh index 3cd43d6ba..ecbb3b907 100644 --- a/sdata/dist-arch/install-deps.sh +++ b/sdata/dist-arch/install-deps.sh @@ -43,6 +43,11 @@ if ! command -v pacman >/dev/null 2>&1; then exit 1 fi +# Keep makepkg from resetting sudo credentials +if [[ -z "${PACMAN_AUTH:-}" ]]; then + export PACMAN_AUTH="sudo" +fi + showfun remove_deprecated_dependencies v remove_deprecated_dependencies