1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-05 21:15:38 -05:00

Compare commits

...

11 Commits

Author SHA1 Message Date
bbedward
0864179085 media: change icon for player volume 2025-11-25 15:02:59 -05:00
bbedward
8de77f283d niri: fix exit anims on overview launcher 2025-11-25 14:54:29 -05:00
bbedward
004a014000 windows: add minimum sizes 2025-11-25 13:58:08 -05:00
bbedward
80f6eb94aa appdrawer: fix not getting mouse events sometimes 2025-11-25 12:25:40 -05:00
bbedward
4035c9cc5f plugins: fix reactivity, tooltips, new IPCs to reload 2025-11-25 11:02:38 -05:00
bbedward
3a365f6807 settings: make plugin browser and widget browser floating 2025-11-25 10:33:32 -05:00
purian23
9920a0a59f Tweak Workflows 2025-11-25 10:09:11 -05:00
github-actions[bot]
c17bb9e171 chore: update packaging versions
🤖 Automated update by GitHub Actions
Workflow run: https://github.com/AvengeMedia/DankMaterialShell/actions/runs/19673220228
2025-11-25 14:37:10 +00:00
purian23
03073f6875 Refactor distro logic & automation 2025-11-25 09:32:24 -05:00
bbedward
609caf6e5f windows: disable QT CSD 2025-11-25 09:24:40 -05:00
bbedward
411141ff88 wallpaper: fix cycling
fixes #812
2025-11-25 09:24:00 -05:00
31 changed files with 1949 additions and 2052 deletions

View File

@@ -153,15 +153,34 @@ jobs:
echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
fi
- name: Update version in packaging files
- name: Update dms-git spec version
if: contains(steps.packages.outputs.packages, 'dms-git') || steps.packages.outputs.packages == 'all'
run: |
# Get commit info for dms-git versioning
COMMIT_HASH=$(git rev-parse --short=8 HEAD)
COMMIT_COUNT=$(git rev-list --count HEAD)
BASE_VERSION=$(grep -oP '^Version:\s+\K[0-9.]+' distro/opensuse/dms.spec | head -1 || echo "0.6.2")
NEW_VERSION="${BASE_VERSION}+git${COMMIT_COUNT}.${COMMIT_HASH}"
echo "📦 Updating dms-git.spec to version: $NEW_VERSION"
# Update version in spec
sed -i "s/^Version:.*/Version: $NEW_VERSION/" distro/opensuse/dms-git.spec
# Add changelog entry
DATE_STR=$(date "+%a %b %d %Y")
CHANGELOG_ENTRY="* $DATE_STR Avenge Media <AvengeMedia.US@gmail.com> - ${NEW_VERSION}-1\n- Git snapshot (commit $COMMIT_COUNT: $COMMIT_HASH)"
sed -i "/%changelog/a\\$CHANGELOG_ENTRY" distro/opensuse/dms-git.spec
- name: Update dms stable version
if: steps.packages.outputs.version != ''
run: |
VERSION="${{ steps.packages.outputs.version }}"
VERSION_NO_V="${VERSION#v}"
echo "Updating packaging to version $VERSION_NO_V"
# Update openSUSE spec files
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/*.spec
# Update openSUSE dms spec (stable only)
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
# Update Debian _service files
for service in distro/debian/*/_service; do
@@ -169,11 +188,6 @@ jobs:
sed -i "s|<param name=\"revision\">v[0-9.]*</param>|<param name=\"revision\">$VERSION</param>|" "$service"
fi
done
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add distro/
git commit -m "chore: update packaging to $VERSION" || echo "No changes to commit"
- name: Install OSC
run: |
@@ -203,13 +217,11 @@ jobs:
MESSAGE="Update to ${{ steps.packages.outputs.version }}"
fi
cd distro
if [[ "$PACKAGES" == "all" ]]; then
bash scripts/obs-upload.sh dms "$MESSAGE"
bash scripts/obs-upload.sh dms-git "Automated git update"
bash distro/scripts/obs-upload.sh dms "$MESSAGE"
bash distro/scripts/obs-upload.sh dms-git "Automated git update"
else
bash scripts/obs-upload.sh "$PACKAGES" "$MESSAGE"
bash distro/scripts/obs-upload.sh "$PACKAGES" "$MESSAGE"
fi
- name: Summary

View File

@@ -63,8 +63,6 @@ jobs:
run: |
PACKAGES="${{ steps.packages.outputs.packages }}"
cd distro/ubuntu/ppa
if [[ "$PACKAGES" == "all" ]]; then
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Uploading dms to PPA..."
@@ -72,19 +70,19 @@ jobs:
echo "🔄 Using rebuild release number: ppa$REBUILD_RELEASE"
fi
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bash create-and-upload.sh "../dms" dms questing
bash distro/scripts/ppa-upload.sh "distro/ubuntu/dms" dms questing
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Uploading dms-git to PPA..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bash create-and-upload.sh "../dms-git" dms-git questing
bash distro/scripts/ppa-upload.sh "distro/ubuntu/dms-git" dms-git questing
else
PPA_NAME="$PACKAGES"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Uploading $PACKAGES to PPA..."
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
bash create-and-upload.sh "../$PACKAGES" "$PPA_NAME" questing
bash distro/scripts/ppa-upload.sh "distro/ubuntu/$PACKAGES" "$PPA_NAME" questing
fi
- name: Summary

View File

@@ -15,7 +15,7 @@
[![GitHub release](https://img.shields.io/github/v/release/AvengeMedia/DankMaterialShell?style=for-the-badge&labelColor=101418&color=9ccbfb)](https://github.com/AvengeMedia/DankMaterialShell/releases)
[![AUR version](https://img.shields.io/aur/version/dms-shell-bin?style=for-the-badge&labelColor=101418&color=9ccbfb)](https://aur.archlinux.org/packages/dms-shell-bin)
[![AUR version (git)](https://img.shields.io/aur/version/dms-shell-git?style=for-the-badge&labelColor=101418&color=9ccbfb&label=AUR%20(git))](https://aur.archlinux.org/packages/dms-shell-git)
[![Ko-Fi donate](https://img.shields.io/badge/donate-kofi?style=for-the-badge&logo=ko-fi&logoColor=ffffff&label=ko-fi&labelColor=101418&color=f16061&link=https%3A%2F%2Fko-fi.com%2Favengemediallc)](https://ko-fi.com/avengemediallc)
[![Ko-Fi donate](https://img.shields.io/badge/donate-kofi?style=for-the-badge&logo=ko-fi&logoColor=ffffff&label=ko-fi&labelColor=101418&color=f16061&link=https%3A%2F%2Fko-fi.com%2Fdanklinux)](https://ko-fi.com/danklinux)
</div>

View File

@@ -1,7 +1,7 @@
%global debug_package %{nil}
Name: dms-git
Version: 0.6.2+git
Version: 0.6.2+git2147.03073f68
Release: 5%{?dist}
Epoch: 1
Summary: DankMaterialShell - Material 3 inspired shell (git nightly)
@@ -102,6 +102,8 @@ fi
%{_userunitdir}/dms.service
%changelog
* Tue Nov 25 2025 Avenge Media <AvengeMedia.US@gmail.com> - 0.6.2+git2147.03073f68-1
- Git snapshot (commit 2147: 03073f68)
* Fri Nov 22 2025 AvengeMedia <maintainer@avengemedia.com> - 0.6.2+git-5
- Git nightly build from master branch
- Multi-arch support (x86_64, aarch64)

0
distro/scripts/obs-status.sh Normal file → Executable file
View File

0
distro/scripts/obs-upload.sh Normal file → Executable file
View File

View File

@@ -1,5 +1,5 @@
#!/bin/bash
# Generic PPA uploader for DMS packages
# Ubuntu PPA uploader for DMS packages
# Usage: ./upload-ppa.sh <changes-file> <ppa-name>
#
# Example:

View File

@@ -53,8 +53,8 @@ PPA_NAME="${ARGS[1]}"
UBUNTU_SERIES="${ARGS[2]:-questing}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_SCRIPT="$SCRIPT_DIR/create-source.sh"
UPLOAD_SCRIPT="$SCRIPT_DIR/upload-ppa.sh"
BUILD_SCRIPT="$SCRIPT_DIR/ppa-build.sh"
UPLOAD_SCRIPT="$SCRIPT_DIR/ppa-dput.sh"
# Validate scripts exist
if [ ! -f "$BUILD_SCRIPT" ]; then

View File

@@ -1,169 +0,0 @@
#!/bin/bash
# Manual testing script for DMS packaging
# Tests OBS (Debian/openSUSE) and PPA (Ubuntu) workflows
# Usage: ./distro/test-packaging.sh [obs|ppa|all]
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
DISTRO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
REPO_ROOT="$(cd "$DISTRO_DIR/.." && pwd)"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
TEST_MODE="${1:-all}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "DMS Packaging Test Suite"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Test 1: OBS Upload (Debian + openSUSE)
if [[ "$TEST_MODE" == "obs" ]] || [[ "$TEST_MODE" == "all" ]]; then
echo "═══════════════════════════════════════════════════════════════════"
echo "TEST 1: OBS Upload (Debian + openSUSE)"
echo "═══════════════════════════════════════════════════════════════════"
echo ""
OBS_SCRIPT="$SCRIPT_DIR/obs-upload.sh"
if [[ ! -f "$OBS_SCRIPT" ]]; then
error "OBS script not found: $OBS_SCRIPT"
exit 1
fi
info "OBS script location: $OBS_SCRIPT"
info "Available packages: dms, dms-git"
echo ""
warn "This will upload to OBS (home:AvengeMedia)"
read -p "Continue with OBS test? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
info "Select package to test:"
echo " 1. dms (stable)"
echo " 2. dms-git (nightly)"
echo " 3. all (both packages)"
read -p "Choice [1]: " -n 1 -r PKG_CHOICE
echo
echo ""
PKG_CHOICE="${PKG_CHOICE:-1}"
cd "$REPO_ROOT"
case "$PKG_CHOICE" in
1)
info "Testing OBS upload for 'dms' package..."
bash "$OBS_SCRIPT" dms "Test packaging update"
;;
2)
info "Testing OBS upload for 'dms-git' package..."
bash "$OBS_SCRIPT" dms-git "Test packaging update"
;;
3)
info "Testing OBS upload for all packages..."
bash "$OBS_SCRIPT" all "Test packaging update"
;;
*)
error "Invalid choice"
exit 1
;;
esac
echo ""
success "OBS test completed"
echo ""
info "Check build status: https://build.opensuse.org/project/monitor/home:AvengeMedia"
else
warn "OBS test skipped"
fi
echo ""
fi
# Test 2: PPA Upload (Ubuntu)
if [[ "$TEST_MODE" == "ppa" ]] || [[ "$TEST_MODE" == "all" ]]; then
echo "═══════════════════════════════════════════════════════════════════"
echo "TEST 2: PPA Upload (Ubuntu)"
echo "═══════════════════════════════════════════════════════════════════"
echo ""
PPA_SCRIPT="$DISTRO_DIR/ubuntu/ppa/create-and-upload.sh"
if [[ ! -f "$PPA_SCRIPT" ]]; then
error "PPA script not found: $PPA_SCRIPT"
exit 1
fi
info "PPA script location: $PPA_SCRIPT"
info "Available PPAs: dms, dms-git"
info "Ubuntu series: questing (25.10)"
echo ""
warn "This will upload to Launchpad PPA (ppa:avengemedia/dms)"
read -p "Continue with PPA test? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
info "Select package to test:"
echo " 1. dms (stable)"
echo " 2. dms-git (nightly)"
read -p "Choice [1]: " -n 1 -r PKG_CHOICE
echo
echo ""
PKG_CHOICE="${PKG_CHOICE:-1}"
case "$PKG_CHOICE" in
1)
info "Testing PPA upload for 'dms' package..."
DMS_PKG="$DISTRO_DIR/ubuntu/dms"
PPA_NAME="dms"
;;
2)
info "Testing PPA upload for 'dms-git' package..."
DMS_PKG="$DISTRO_DIR/ubuntu/dms-git"
PPA_NAME="dms-git"
;;
*)
error "Invalid choice"
exit 1
;;
esac
echo ""
if [[ ! -d "$DMS_PKG" ]]; then
error "DMS package directory not found: $DMS_PKG"
exit 1
fi
bash "$PPA_SCRIPT" "$DMS_PKG" "$PPA_NAME" questing
echo ""
success "PPA test completed"
echo ""
info "Check build status: https://launchpad.net/~avengemedia/+archive/ubuntu/dms/+packages"
else
warn "PPA test skipped"
fi
echo ""
fi
# Summary
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Testing Summary"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"

View File

@@ -601,4 +601,61 @@ Item {
target: "widget"
}
IpcHandler {
function reload(pluginId: string): string {
if (!pluginId)
return "ERROR: No plugin ID specified";
if (!PluginService.availablePlugins[pluginId])
return `PLUGIN_NOT_FOUND: ${pluginId}`;
if (!PluginService.isPluginLoaded(pluginId))
return `PLUGIN_NOT_LOADED: ${pluginId}`;
const success = PluginService.reloadPlugin(pluginId);
return success ? `PLUGIN_RELOAD_SUCCESS: ${pluginId}` : `PLUGIN_RELOAD_FAILED: ${pluginId}`;
}
function enable(pluginId: string): string {
if (!pluginId)
return "ERROR: No plugin ID specified";
if (!PluginService.availablePlugins[pluginId])
return `PLUGIN_NOT_FOUND: ${pluginId}`;
const success = PluginService.enablePlugin(pluginId);
return success ? `PLUGIN_ENABLE_SUCCESS: ${pluginId}` : `PLUGIN_ENABLE_FAILED: ${pluginId}`;
}
function disable(pluginId: string): string {
if (!pluginId)
return "ERROR: No plugin ID specified";
if (!PluginService.availablePlugins[pluginId])
return `PLUGIN_NOT_FOUND: ${pluginId}`;
const success = PluginService.disablePlugin(pluginId);
return success ? `PLUGIN_DISABLE_SUCCESS: ${pluginId}` : `PLUGIN_DISABLE_FAILED: ${pluginId}`;
}
function list(): string {
const plugins = PluginService.getAvailablePlugins();
if (plugins.length === 0)
return "No plugins available";
return plugins.map(p => `${p.id} [${p.loaded ? "loaded" : "disabled"}]`).join("\n");
}
function status(pluginId: string): string {
if (!pluginId)
return "ERROR: No plugin ID specified";
if (!PluginService.availablePlugins[pluginId])
return `PLUGIN_NOT_FOUND: ${pluginId}`;
return PluginService.isPluginLoaded(pluginId) ? "loaded" : "disabled";
}
target: "plugins"
}
}

View File

@@ -3,10 +3,8 @@ import QtCore
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Io
import qs.Common
import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets
FloatingWindow {
@@ -215,6 +213,7 @@ FloatingWindow {
objectName: "fileBrowserModal"
title: "Files - " + browserTitle
minimumSize: Qt.size(500, 400)
implicitWidth: 800
implicitHeight: 600
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)

View File

@@ -42,6 +42,7 @@ FloatingWindow {
objectName: "processListModal"
title: I18n.tr("System Monitor", "sysmon window title")
minimumSize: Qt.size(650, 400)
implicitWidth: 900
implicitHeight: 680
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)

View File

@@ -39,6 +39,7 @@ FloatingWindow {
objectName: "settingsModal"
title: I18n.tr("Settings", "settings window title")
minimumSize: Qt.size(500, 400)
implicitWidth: 800
implicitHeight: 800
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Modals.Spotlight
import qs.Modules.AppDrawer
@@ -17,33 +16,33 @@ Item {
function resetScroll() {
if (searchMode === "apps") {
resultsView.resetScroll()
resultsView.resetScroll();
} else {
fileSearchResults.resetScroll()
fileSearchResults.resetScroll();
}
}
function updateSearchMode() {
if (searchField.text.startsWith("/")) {
if (searchMode !== "files") {
searchMode = "files"
searchMode = "files";
}
const query = searchField.text.substring(1)
fileSearchController.searchQuery = query
const query = searchField.text.substring(1);
fileSearchController.searchQuery = query;
} else {
if (searchMode !== "apps") {
searchMode = "apps"
fileSearchController.reset()
appLauncher.searchQuery = searchField.text
searchMode = "apps";
fileSearchController.reset();
appLauncher.searchQuery = searchField.text;
}
}
}
onSearchModeChanged: {
if (searchMode === "files") {
appLauncher.keyboardNavigationActive = false
appLauncher.keyboardNavigationActive = false;
} else {
fileSearchController.keyboardNavigationActive = false
fileSearchController.keyboardNavigationActive = false;
}
}
@@ -51,104 +50,104 @@ Item {
focus: true
clip: false
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
if (parentModal)
parentModal.hide()
if (event.key === Qt.Key_Escape) {
if (parentModal)
parentModal.hide();
event.accepted = true
} else if (event.key === Qt.Key_Down) {
if (searchMode === "apps") {
appLauncher.selectNext()
} else {
fileSearchController.selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_Up) {
if (searchMode === "apps") {
appLauncher.selectPrevious()
} else {
fileSearchController.selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_Right && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
event.accepted = true
} else if (event.key === Qt.Key_Left && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
appLauncher.selectNext()
} else {
fileSearchController.selectNext()
}
event.accepted = true
} else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
appLauncher.selectPrevious()
} else {
fileSearchController.selectPrevious()
}
event.accepted = true
} else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
event.accepted = true
} else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
event.accepted = true
} else if (event.key === Qt.Key_Tab) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
} else {
appLauncher.selectNext()
}
} else {
fileSearchController.selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_Backtab) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
} else {
appLauncher.selectPrevious()
}
} else {
fileSearchController.selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow()
} else {
appLauncher.selectNext()
}
} else {
fileSearchController.selectNext()
}
event.accepted = true
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow()
} else {
appLauncher.selectPrevious()
}
} else {
fileSearchController.selectPrevious()
}
event.accepted = true
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (searchMode === "apps") {
appLauncher.launchSelected()
} else if (searchMode === "files") {
fileSearchController.openSelected()
}
event.accepted = true
}
}
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
if (searchMode === "apps") {
appLauncher.selectNext();
} else {
fileSearchController.selectNext();
}
event.accepted = true;
} else if (event.key === Qt.Key_Up) {
if (searchMode === "apps") {
appLauncher.selectPrevious();
} else {
fileSearchController.selectPrevious();
}
event.accepted = true;
} else if (event.key === Qt.Key_Right && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Left && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow();
event.accepted = true;
} else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
appLauncher.selectNext();
} else {
fileSearchController.selectNext();
}
event.accepted = true;
} else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
appLauncher.selectPrevious();
} else {
fileSearchController.selectPrevious();
}
event.accepted = true;
} else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow();
event.accepted = true;
} else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && searchMode === "apps" && appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Tab) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow();
} else {
appLauncher.selectNext();
}
} else {
fileSearchController.selectNext();
}
event.accepted = true;
} else if (event.key === Qt.Key_Backtab) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow();
} else {
appLauncher.selectPrevious();
}
} else {
fileSearchController.selectPrevious();
}
event.accepted = true;
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectNextInRow();
} else {
appLauncher.selectNext();
}
} else {
fileSearchController.selectNext();
}
event.accepted = true;
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
if (searchMode === "apps") {
if (appLauncher.viewMode === "grid") {
appLauncher.selectPreviousInRow();
} else {
appLauncher.selectPrevious();
}
} else {
fileSearchController.selectPrevious();
}
event.accepted = true;
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (searchMode === "apps") {
appLauncher.launchSelected();
} else if (searchMode === "files") {
fileSearchController.openSelected();
}
event.accepted = true;
}
}
AppLauncher {
id: appLauncher
@@ -156,29 +155,27 @@ Item {
viewMode: SettingsData.spotlightModalViewMode
gridColumns: SettingsData.appLauncherGridColumns
onAppLaunched: () => {
if (parentModal)
parentModal.hide()
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview()
}
}
if (parentModal)
parentModal.hide();
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview();
}
}
onViewModeSelected: mode => {
SettingsData.set("spotlightModalViewMode", mode)
}
SettingsData.set("spotlightModalViewMode", mode);
}
}
FileSearchController {
id: fileSearchController
onFileOpened: () => {
if (parentModal)
parentModal.hide()
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview()
}
}
if (parentModal)
parentModal.hide();
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview();
}
}
}
Column {
@@ -216,34 +213,33 @@ Item {
keyForwardTargets: [spotlightKeyHandler]
onTextChanged: {
if (searchMode === "apps") {
appLauncher.searchQuery = text
appLauncher.searchQuery = text;
}
}
onTextEdited: {
updateSearchMode()
updateSearchMode();
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
if (parentModal)
parentModal.hide()
if (event.key === Qt.Key_Escape) {
if (parentModal)
parentModal.hide();
event.accepted = true
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length > 0) {
if (searchMode === "apps") {
if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0)
appLauncher.launchSelected()
else if (appLauncher.model.count > 0)
appLauncher.launchApp(appLauncher.model.get(0))
} else if (searchMode === "files") {
if (fileSearchController.model.count > 0)
fileSearchController.openSelected()
}
event.accepted = true
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key
=== Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false
}
}
event.accepted = true;
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length > 0) {
if (searchMode === "apps") {
if (appLauncher.keyboardNavigationActive && appLauncher.model.count > 0)
appLauncher.launchSelected();
else if (appLauncher.model.count > 0)
appLauncher.launchApp(appLauncher.model.get(0));
} else if (searchMode === "files") {
if (fileSearchController.model.count > 0)
fileSearchController.openSelected();
}
event.accepted = true;
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false;
}
}
}
Row {
@@ -271,8 +267,8 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
appLauncher.setViewMode("list")
}
appLauncher.setViewMode("list");
}
}
}
@@ -296,8 +292,8 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
appLauncher.setViewMode("grid")
}
appLauncher.setViewMode("grid");
}
}
}
}
@@ -329,22 +325,22 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
fileSearchController.searchField = "filename"
}
fileSearchController.searchField = "filename";
}
onEntered: {
filenameTooltipLoader.active = true
filenameTooltipLoader.active = true;
Qt.callLater(() => {
if (filenameTooltipLoader.item) {
const p = mapToItem(null, width / 2, height + Theme.spacingXS)
filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null)
}
})
if (filenameTooltipLoader.item) {
const p = mapToItem(null, width / 2, height + Theme.spacingXS);
filenameTooltipLoader.item.show(I18n.tr("Search filenames"), p.x, p.y, null);
}
});
}
onExited: {
if (filenameTooltipLoader.item)
filenameTooltipLoader.item.hide()
filenameTooltipLoader.item.hide();
filenameTooltipLoader.active = false
filenameTooltipLoader.active = false;
}
}
}
@@ -371,22 +367,22 @@ Item {
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: () => {
fileSearchController.searchField = "body"
}
fileSearchController.searchField = "body";
}
onEntered: {
contentTooltipLoader.active = true
contentTooltipLoader.active = true;
Qt.callLater(() => {
if (contentTooltipLoader.item) {
const p = mapToItem(null, width / 2, height + Theme.spacingXS)
contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null)
}
})
if (contentTooltipLoader.item) {
const p = mapToItem(null, width / 2, height + Theme.spacingXS);
contentTooltipLoader.item.show(I18n.tr("Search file contents"), p.x, p.y, null);
}
});
}
onExited: {
if (contentTooltipLoader.item)
contentTooltipLoader.item.hide()
contentTooltipLoader.item.hide();
contentTooltipLoader.active = false
contentTooltipLoader.active = false;
}
}
}
@@ -426,8 +422,8 @@ Item {
visible: contextMenu.visible
z: 999
onClicked: () => {
contextMenu.hide()
}
contextMenu.hide();
}
MouseArea {

View File

@@ -15,8 +15,6 @@ DankPopout {
layerNamespace: "dms:app-launcher"
property var triggerScreen: null
function show() {
open()
}
@@ -25,21 +23,16 @@ DankPopout {
popupHeight: 600
triggerWidth: 40
positioning: ""
screen: triggerScreen
onBackgroundClicked: close()
onShouldBeVisibleChanged: {
if (shouldBeVisible) {
appLauncher.searchQuery = ""
appLauncher.selectedIndex = 0
appLauncher.setCategory(I18n.tr("All"))
Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.text = ""
contentLoader.item.searchField.forceActiveFocus()
}
})
onOpened: {
appLauncher.searchQuery = ""
appLauncher.selectedIndex = 0
appLauncher.setCategory(I18n.tr("All"))
if (contentLoader.item?.searchField) {
contentLoader.item.searchField.text = ""
contentLoader.item.searchField.forceActiveFocus()
}
}

View File

@@ -179,6 +179,12 @@ Item {
const volume = currentVolume;
if (usePlayerVolume) {
if (volume === 0.0)
return "music_off";
return "music_note";
}
if (volume === 0.0)
return "volume_off";
if (volume <= 0.33)

View File

@@ -1,5 +1,4 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
@@ -76,7 +75,6 @@ Column {
color: Theme.primary
anchors.centerIn: parent
}
}
Item {
@@ -90,7 +88,6 @@ Column {
color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
}
DankFlickable {
@@ -147,11 +144,8 @@ Column {
NumberAnimation {
duration: Theme.shortDuration
}
}
}
}
StyledText {
@@ -163,182 +157,168 @@ Column {
horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
}
}
Rectangle {
Row {
width: parent.width
height: 80
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.width: 1
spacing: Theme.spacingM
Row {
anchors.centerIn: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
Rectangle {
width: (parent.width - Theme.spacingM) / 2
height: 80
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.width: 1
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Row {
anchors.centerIn: parent
spacing: Theme.spacingM
StyledText {
text: I18n.tr("Memory")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: `${DgopService.formatSystemMemory(DgopService.usedMemoryKB)} / ${DgopService.formatSystemMemory(DgopService.totalMemoryKB)}`
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Item {
width: Theme.spacingL
height: 1
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
width: 200
Rectangle {
width: parent.width
height: 16
radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Rectangle {
width: DgopService.totalMemoryKB > 0 ? parent.width * (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0
height: parent.height
radius: parent.radius
color: {
const usage = DgopService.totalMemoryKB > 0 ? (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0;
if (usage > 0.9) {
return Theme.error;
}
if (usage > 0.7) {
return Theme.warning;
}
return Theme.secondary;
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
StyledText {
text: I18n.tr("Memory")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: `${DgopService.formatSystemMemory(DgopService.usedMemoryKB)} / ${DgopService.formatSystemMemory(DgopService.totalMemoryKB)}`
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
StyledText {
text: DgopService.totalMemoryKB > 0 ? `${((DgopService.usedMemoryKB / DgopService.totalMemoryKB) * 100).toFixed(1)}% used` : "No data"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.surfaceText
}
}
Item {
width: Theme.spacingL
height: 1
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
StyledText {
text: I18n.tr("Swap")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: DgopService.totalSwapKB > 0 ? `${DgopService.formatSystemMemory(DgopService.usedSwapKB)} / ${DgopService.formatSystemMemory(DgopService.totalSwapKB)}` : "No swap configured"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Item {
width: Theme.spacingL
height: 1
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
width: 200
Rectangle {
width: parent.width
height: 16
radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
width: 120
Rectangle {
width: DgopService.totalSwapKB > 0 ? parent.width * (DgopService.usedSwapKB / DgopService.totalSwapKB) : 0
height: parent.height
radius: parent.radius
color: {
if (!DgopService.totalSwapKB) {
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3);
width: parent.width
height: 16
radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Rectangle {
width: DgopService.totalMemoryKB > 0 ? parent.width * (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0
height: parent.height
radius: parent.radius
color: {
const usage = DgopService.totalMemoryKB > 0 ? (DgopService.usedMemoryKB / DgopService.totalMemoryKB) : 0;
if (usage > 0.9) {
return Theme.error;
}
if (usage > 0.7) {
return Theme.warning;
}
return Theme.secondary;
}
const usage = DgopService.usedSwapKB / DgopService.totalSwapKB;
if (usage > 0.9) {
return Theme.error;
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
}
}
if (usage > 0.7) {
return Theme.warning;
}
return Theme.info;
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
}
}
}
StyledText {
text: DgopService.totalMemoryKB > 0 ? `${((DgopService.usedMemoryKB / DgopService.totalMemoryKB) * 100).toFixed(1)}% used` : "No data"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.surfaceText
}
}
StyledText {
text: DgopService.totalSwapKB > 0 ? `${((DgopService.usedSwapKB / DgopService.totalSwapKB) * 100).toFixed(1)}% used` : "Not available"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.surfaceText
}
}
}
Rectangle {
width: (parent.width - Theme.spacingM) / 2
height: 80
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.06)
border.width: 1
Row {
anchors.centerIn: parent
spacing: Theme.spacingM
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
StyledText {
text: I18n.tr("Swap")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Bold
color: Theme.surfaceText
}
StyledText {
text: DgopService.totalSwapKB > 0 ? `${DgopService.formatSystemMemory(DgopService.usedSwapKB)} / ${DgopService.formatSystemMemory(DgopService.totalSwapKB)}` : "No swap"
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
width: 120
Rectangle {
width: parent.width
height: 16
radius: 8
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
Rectangle {
width: DgopService.totalSwapKB > 0 ? parent.width * (DgopService.usedSwapKB / DgopService.totalSwapKB) : 0
height: parent.height
radius: parent.radius
color: {
if (!DgopService.totalSwapKB) {
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3);
}
const usage = DgopService.usedSwapKB / DgopService.totalSwapKB;
if (usage > 0.9) {
return Theme.error;
}
if (usage > 0.7) {
return Theme.warning;
}
return Theme.info;
}
Behavior on width {
NumberAnimation {
duration: Theme.mediumDuration
}
}
}
}
StyledText {
text: DgopService.totalSwapKB > 0 ? `${((DgopService.usedSwapKB / DgopService.totalSwapKB) * 100).toFixed(1)}% used` : "N/A"
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Bold
color: Theme.surfaceText
}
}
}
}
}
Row {
@@ -385,7 +365,6 @@ Column {
font.weight: Font.Bold
color: Theme.surfaceText
}
}
Row {
@@ -403,13 +382,9 @@ Column {
font.weight: Font.Bold
color: Theme.surfaceText
}
}
}
}
}
Rectangle {
@@ -451,7 +426,6 @@ Column {
font.weight: Font.Bold
color: Theme.surfaceText
}
}
Row {
@@ -469,15 +443,9 @@ Column {
font.weight: Font.Bold
color: Theme.surfaceText
}
}
}
}
}
}
}

View File

@@ -194,9 +194,9 @@ Item {
// ! Hacky workaround because we want to re-register any vertical bars after changing a hBar
// ! That allows them to re-make with the right exclusiveZone
function notifyHorizontalBarChange() {
if (!selectedBarIsVertical) {
horizontalBarChangeDebounce.restart();
}
if (selectedBarIsVertical)
return;
horizontalBarChangeDebounce.restart();
}
function createNewBar() {
@@ -290,38 +290,44 @@ Item {
}
function getWidgetsForSection(sectionId) {
if (sectionId === "left")
switch (sectionId) {
case "left":
return selectedBarConfig?.leftWidgets || [];
if (sectionId === "center")
case "center":
return selectedBarConfig?.centerWidgets || [];
if (sectionId === "right")
case "right":
return selectedBarConfig?.rightWidgets || [];
return [];
default:
return [];
}
}
function setWidgetsForSection(sectionId, widgets) {
if (sectionId === "left")
switch (sectionId) {
case "left":
SettingsData.updateBarConfig(selectedBarId, {
leftWidgets: widgets
});
else if (sectionId === "center")
break;
case "center":
SettingsData.updateBarConfig(selectedBarId, {
centerWidgets: widgets
});
else if (sectionId === "right")
break;
case "right":
SettingsData.updateBarConfig(selectedBarId, {
rightWidgets: widgets
});
break;
}
}
function getWidgetsForPopup() {
return baseWidgetDefinitions.filter(widget => {
if (widget.warning && widget.warning.includes("Plugin is disabled")) {
if (widget.warning && widget.warning.includes("Plugin is disabled"))
return false;
}
if (widget.enabled === false) {
if (widget.enabled === false)
return false;
}
return true;
});
}
@@ -646,36 +652,38 @@ Item {
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i];
var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId === itemId) {
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": enabled
};
} else {
var newWidget = {
"id": widget.id,
"enabled": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
else if (widget.id === "gpuTemp")
newWidget.selectedGpuIndex = 0;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
else if (widget.id === "gpuTemp")
newWidget.pciId = "";
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
}
widgets[i] = newWidget;
}
if (widgetId !== itemId)
continue;
if (typeof widget === "string") {
widgets[i] = {
"id": widget,
"enabled": enabled
};
break;
}
var newWidget = {
"id": widget.id,
"enabled": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
else if (widget.id === "gpuTemp")
newWidget.selectedGpuIndex = 0;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
else if (widget.id === "gpuTemp")
newWidget.pciId = "";
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[i] = newWidget;
break;
}
setWidgetsForSection(sectionId, widgets);
}
@@ -686,227 +694,251 @@ Item {
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId === "spacer") {
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"size": newSize
};
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"size": newSize
};
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
}
widgets[widgetIndex] = newWidget;
}
}
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var widget = widgets[widgetIndex];
var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId !== "spacer") {
setWidgetsForSection(sectionId, widgets);
return;
}
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"size": newSize
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"size": newSize
};
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"selectedGpuIndex": selectedGpuIndex,
"pciId": DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""
};
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"selectedGpuIndex": selectedGpuIndex,
"pciId": DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : ""
};
if (widget.size !== undefined)
newWidget.size = widget.size;
widgets[widgetIndex] = newWidget;
}
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var pciId = DgopService.availableGpus && DgopService.availableGpus.length > selectedGpuIndex ? DgopService.availableGpus[selectedGpuIndex].pciId : "";
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"selectedGpuIndex": selectedGpuIndex,
"pciId": pciId
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"selectedGpuIndex": selectedGpuIndex,
"pciId": pciId
};
if (widget.size !== undefined)
newWidget.size = widget.size;
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"mountPath": mountPath
};
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"mountPath": mountPath
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
}
widgets[widgetIndex] = newWidget;
}
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"mountPath": mountPath
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"mountPath": mountPath
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) {
switch (settingName) {
case "showNetworkIcon":
SettingsData.set("controlCenterShowNetworkIcon", value)
break
SettingsData.set("controlCenterShowNetworkIcon", value);
break;
case "showBluetoothIcon":
SettingsData.set("controlCenterShowBluetoothIcon", value)
break
SettingsData.set("controlCenterShowBluetoothIcon", value);
break;
case "showAudioIcon":
SettingsData.set("controlCenterShowAudioIcon", value)
break
SettingsData.set("controlCenterShowAudioIcon", value);
break;
case "showVpnIcon":
SettingsData.set("controlCenterShowVpnIcon", value)
break
SettingsData.set("controlCenterShowVpnIcon", value);
break;
case "showBrightnessIcon":
SettingsData.set("controlCenterShowBrightnessIcon", value)
break
SettingsData.set("controlCenterShowBrightnessIcon", value);
break;
case "showMicIcon":
SettingsData.set("controlCenterShowMicIcon", value)
break
SettingsData.set("controlCenterShowMicIcon", value);
break;
case "showBatteryIcon":
SettingsData.set("controlCenterShowBatteryIcon", value)
break
SettingsData.set("controlCenterShowBatteryIcon", value);
break;
case "showPrinterIcon":
SettingsData.set("controlCenterShowPrinterIcon", value)
break
SettingsData.set("controlCenterShowPrinterIcon", value);
break;
}
}
function handlePrivacySettingChanged(sectionId, widgetIndex, settingName, value) {
if (settingName === "showMicIcon") {
switch (settingName) {
case "showMicIcon":
SettingsData.set("privacyShowMicIcon", value);
} else if (settingName === "showCameraIcon") {
break;
case "showCameraIcon":
SettingsData.set("privacyShowCameraIcon", value);
} else if (settingName === "showScreenSharingIcon") {
break;
case "showScreenSharingIcon":
SettingsData.set("privacyShowScreenShareIcon", value);
break;
}
}
function handleMinimumWidthChanged(sectionId, widgetIndex, enabled) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"minimumWidth": enabled
};
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"minimumWidth": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.showSwap !== undefined)
newWidget.showSwap = widget.showSwap;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
}
widgets[widgetIndex] = newWidget;
}
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"minimumWidth": enabled
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"minimumWidth": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.showSwap !== undefined)
newWidget.showSwap = widget.showSwap;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
function handleShowSwapChanged(sectionId, widgetIndex, enabled) {
var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"showSwap": enabled
};
} else {
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"showSwap": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.minimumWidth !== undefined)
newWidget.minimumWidth = widget.minimumWidth;
if (widget.mediaSize !== undefined)
newWidget.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
newWidget.clockCompactMode = widget.clockCompactMode;
if (widget.focusedWindowCompactMode !== undefined)
newWidget.focusedWindowCompactMode = widget.focusedWindowCompactMode;
if (widget.runningAppsCompactMode !== undefined)
newWidget.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
}
widgets[widgetIndex] = newWidget;
}
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
setWidgetsForSection(sectionId, widgets);
return;
}
var widget = widgets[widgetIndex];
if (typeof widget === "string") {
widgets[widgetIndex] = {
"id": widget,
"enabled": true,
"showSwap": enabled
};
setWidgetsForSection(sectionId, widgets);
return;
}
var newWidget = {
"id": widget.id,
"enabled": widget.enabled,
"showSwap": enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
newWidget.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
newWidget.pciId = widget.pciId;
if (widget.mountPath !== undefined)
newWidget.mountPath = widget.mountPath;
if (widget.minimumWidth !== undefined)
newWidget.minimumWidth = widget.minimumWidth;
if (widget.mediaSize !== undefined)
newWidget.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
newWidget.clockCompactMode = widget.clockCompactMode;
if (widget.focusedWindowCompactMode !== undefined)
newWidget.focusedWindowCompactMode = widget.focusedWindowCompactMode;
if (widget.runningAppsCompactMode !== undefined)
newWidget.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[widgetIndex] = newWidget;
setWidgetsForSection(sectionId, widgets);
}
@@ -932,7 +964,6 @@ Item {
"id": widget.id,
"enabled": widget.enabled
};
if (widget.size !== undefined)
newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
@@ -956,11 +987,10 @@ Item {
if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true;
newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon ?? true;
}
widgets[i] = newWidget;
widget = newWidget;
}
@@ -993,59 +1023,45 @@ Item {
var widgets = [];
var widgetData = getWidgetsForSection(sectionId);
widgetData.forEach(widget => {
var widgetId = typeof widget === "string" ? widget : widget.id;
var widgetEnabled = typeof widget === "string" ? true : widget.enabled;
var widgetSize = typeof widget === "string" ? undefined : widget.size;
var widgetSelectedGpuIndex = typeof widget === "string" ? undefined : widget.selectedGpuIndex;
var widgetPciId = typeof widget === "string" ? undefined : widget.pciId;
var widgetMountPath = typeof widget === "string" ? undefined : widget.mountPath;
var widgetShowNetworkIcon = typeof widget === "string" ? undefined : widget.showNetworkIcon;
var widgetShowBluetoothIcon = typeof widget === "string" ? undefined : widget.showBluetoothIcon;
var widgetShowAudioIcon = typeof widget === "string" ? undefined : widget.showAudioIcon;
var widgetMinimumWidth = typeof widget === "string" ? undefined : widget.minimumWidth;
var widgetShowSwap = typeof widget === "string" ? undefined : widget.showSwap;
var widgetMediaSize = typeof widget === "string" ? undefined : widget.mediaSize;
var widgetClockCompactMode = typeof widget === "string" ? undefined : widget.clockCompactMode;
var widgetFocusedWindowCompactMode = typeof widget === "string" ? undefined : widget.focusedWindowCompactMode;
var widgetRunningAppsCompactMode = typeof widget === "string" ? undefined : widget.runningAppsCompactMode;
var widgetKeyboardLayoutNameCompactMode = typeof widget === "string" ? undefined : widget.keyboardLayoutNameCompactMode;
var widgetDef = baseWidgetDefinitions.find(w => {
return w.id === widgetId;
});
if (widgetDef) {
var item = Object.assign({}, widgetDef);
item.enabled = widgetEnabled;
if (widgetSize !== undefined)
item.size = widgetSize;
if (widgetSelectedGpuIndex !== undefined)
item.selectedGpuIndex = widgetSelectedGpuIndex;
if (widgetPciId !== undefined)
item.pciId = widgetPciId;
if (widgetMountPath !== undefined)
item.mountPath = widgetMountPath;
if (widgetShowNetworkIcon !== undefined)
item.showNetworkIcon = widgetShowNetworkIcon;
if (widgetShowBluetoothIcon !== undefined)
item.showBluetoothIcon = widgetShowBluetoothIcon;
if (widgetShowAudioIcon !== undefined)
item.showAudioIcon = widgetShowAudioIcon;
if (widgetMinimumWidth !== undefined)
item.minimumWidth = widgetMinimumWidth;
if (widgetShowSwap !== undefined)
item.showSwap = widgetShowSwap;
if (widgetMediaSize !== undefined)
item.mediaSize = widgetMediaSize;
if (widgetClockCompactMode !== undefined)
item.clockCompactMode = widgetClockCompactMode;
if (widgetFocusedWindowCompactMode !== undefined)
item.focusedWindowCompactMode = widgetFocusedWindowCompactMode;
if (widgetRunningAppsCompactMode !== undefined)
item.runningAppsCompactMode = widgetRunningAppsCompactMode;
if (widgetKeyboardLayoutNameCompactMode !== undefined)
item.keyboardLayoutNameCompactMode = widgetKeyboardLayoutNameCompactMode;
var isString = typeof widget === "string";
var widgetId = isString ? widget : widget.id;
var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId);
if (!widgetDef)
return;
widgets.push(item);
var item = Object.assign({}, widgetDef);
item.enabled = isString ? true : widget.enabled;
if (!isString) {
if (widget.size !== undefined)
item.size = widget.size;
if (widget.selectedGpuIndex !== undefined)
item.selectedGpuIndex = widget.selectedGpuIndex;
if (widget.pciId !== undefined)
item.pciId = widget.pciId;
if (widget.mountPath !== undefined)
item.mountPath = widget.mountPath;
if (widget.showNetworkIcon !== undefined)
item.showNetworkIcon = widget.showNetworkIcon;
if (widget.showBluetoothIcon !== undefined)
item.showBluetoothIcon = widget.showBluetoothIcon;
if (widget.showAudioIcon !== undefined)
item.showAudioIcon = widget.showAudioIcon;
if (widget.minimumWidth !== undefined)
item.minimumWidth = widget.minimumWidth;
if (widget.showSwap !== undefined)
item.showSwap = widget.showSwap;
if (widget.mediaSize !== undefined)
item.mediaSize = widget.mediaSize;
if (widget.clockCompactMode !== undefined)
item.clockCompactMode = widget.clockCompactMode;
if (widget.focusedWindowCompactMode !== undefined)
item.focusedWindowCompactMode = widget.focusedWindowCompactMode;
if (widget.runningAppsCompactMode !== undefined)
item.runningAppsCompactMode = widget.runningAppsCompactMode;
if (widget.keyboardLayoutNameCompactMode !== undefined)
item.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
}
widgets.push(item);
});
return widgets;
}
@@ -1139,49 +1155,13 @@ Item {
implicitHeight: 1
}
Rectangle {
id: addBarBtn
width: 100
height: 32
radius: Theme.cornerRadius
color: addBarArea.containsMouse ? Theme.primaryPressed : Theme.primary
DankButton {
text: I18n.tr("Add Bar")
iconName: "add"
buttonHeight: 32
visible: SettingsData.barConfigs.length < 4
Layout.alignment: Qt.AlignVCenter
Row {
anchors.centerIn: parent
spacing: Theme.spacingXS
DankIcon {
name: "add"
size: 14
color: Theme.onPrimary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Add Bar")
font.pixelSize: Theme.fontSizeSmall
font.weight: Font.Medium
color: Theme.onPrimary
anchors.verticalCenter: parent.verticalCenter
}
}
MouseArea {
id: addBarArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: dankBarTab.createNewBar()
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
onClicked: dankBarTab.createNewBar()
}
}
@@ -3284,7 +3264,6 @@ Item {
}
}
// Center/Middle Section
StyledRect {
width: parent.width
height: centerSection.implicitHeight + Theme.spacingL * 2
@@ -3343,7 +3322,6 @@ Item {
}
}
// Right/Bottom Section
StyledRect {
width: parent.width
height: rightSection.implicitHeight + Theme.spacingL * 2

View File

@@ -1,10 +1,7 @@
import QtCore
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import Quickshell
import qs.Common
import qs.Modals
import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets
@@ -1542,7 +1539,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
checked: SessionData.isLightMode
onToggleCompleted: checked => {
onToggled: checked => {
Theme.screenTransition();
Theme.setLightMode(checked);
}

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ StyledRect {
property string expandedPluginId: ""
property bool hasUpdate: false
property bool isReloading: false
property var sharedTooltip: null
property string pluginId: pluginData ? pluginData.id : ""
property string pluginDirectoryName: {
@@ -28,6 +29,10 @@ StyledRect {
property var pluginPermissions: pluginData ? (pluginData.permissions || []) : []
property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== ""
property bool isExpanded: expandedPluginId === pluginId
property bool isLoaded: {
PluginService.loadedPlugins;
return PluginService.loadedPlugins[pluginId] !== undefined;
}
width: parent.width
height: pluginItemColumn.implicitHeight + Theme.spacingM * 2 + settingsContainer.height
@@ -63,7 +68,7 @@ StyledRect {
DankIcon {
name: root.pluginIcon
size: Theme.iconSize
color: PluginService.isPluginLoaded(root.pluginId) ? Theme.primary : Theme.surfaceVariantText
color: root.isLoaded ? Theme.primary : Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter
}
@@ -111,7 +116,7 @@ StyledRect {
height: 28
radius: 14
color: updateArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent"
visible: DMSService.dmsAvailable && PluginService.isPluginLoaded(root.pluginId) && root.hasUpdate
visible: DMSService.dmsAvailable && root.isLoaded && root.hasUpdate
DankIcon {
anchors.centerIn: parent
@@ -131,27 +136,21 @@ StyledRect {
DMSService.update(currentPluginName, response => {
if (response.error) {
ToastService.showError("Update failed: " + response.error);
} else {
ToastService.showInfo("Plugin updated: " + currentPluginName);
PluginService.forceRescanPlugin(currentPluginId);
if (DMSService.apiVersion >= 8) {
DMSService.listInstalled();
}
return;
}
ToastService.showInfo("Plugin updated: " + currentPluginName);
PluginService.forceRescanPlugin(currentPluginId);
if (DMSService.apiVersion >= 8)
DMSService.listInstalled();
});
}
onEntered: {
tooltipLoader.active = true;
if (tooltipLoader.item) {
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Update Plugin"), p.x, p.y - 40, null);
}
if (root.sharedTooltip)
root.sharedTooltip.show(I18n.tr("Update Plugin"), parent, 0, 0, "top");
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
if (root.sharedTooltip)
root.sharedTooltip.hide();
}
}
}
@@ -180,27 +179,21 @@ StyledRect {
DMSService.uninstall(currentPluginName, response => {
if (response.error) {
ToastService.showError("Uninstall failed: " + response.error);
} else {
ToastService.showInfo("Plugin uninstalled: " + currentPluginName);
PluginService.scanPlugins();
if (root.isExpanded) {
root.expandedPluginId = "";
}
return;
}
ToastService.showInfo("Plugin uninstalled: " + currentPluginName);
PluginService.scanPlugins();
if (root.isExpanded)
root.expandedPluginId = "";
});
}
onEntered: {
tooltipLoader.active = true;
if (tooltipLoader.item) {
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Uninstall Plugin"), p.x, p.y - 40, null);
}
if (root.sharedTooltip)
root.sharedTooltip.show(I18n.tr("Uninstall Plugin"), parent, 0, 0, "top");
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
if (root.sharedTooltip)
root.sharedTooltip.hide();
}
}
}
@@ -210,7 +203,7 @@ StyledRect {
height: 28
radius: 14
color: reloadArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent"
visible: PluginService.isPluginLoaded(root.pluginId)
visible: root.isLoaded
DankIcon {
anchors.centerIn: parent
@@ -230,23 +223,18 @@ StyledRect {
root.isReloading = true;
if (PluginService.reloadPlugin(currentPluginId)) {
ToastService.showInfo("Plugin reloaded: " + currentPluginName);
} else {
ToastService.showError("Failed to reload plugin: " + currentPluginName);
root.isReloading = false;
return;
}
ToastService.showError("Failed to reload plugin: " + currentPluginName);
root.isReloading = false;
}
onEntered: {
tooltipLoader.active = true;
if (tooltipLoader.item) {
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Reload Plugin"), p.x, p.y - 40, null);
}
if (root.sharedTooltip)
root.sharedTooltip.show(I18n.tr("Reload Plugin"), parent, 0, 0, "top");
}
onExited: {
if (tooltipLoader.item) {
tooltipLoader.item.hide();
}
tooltipLoader.active = false;
if (root.sharedTooltip)
root.sharedTooltip.hide();
}
}
}
@@ -254,7 +242,7 @@ StyledRect {
DankToggle {
id: pluginToggle
anchors.verticalCenter: parent.verticalCenter
checked: PluginService.isPluginLoaded(root.pluginId)
checked: root.isLoaded
onToggled: isChecked => {
const currentPluginId = root.pluginId;
const currentPluginName = root.pluginName;
@@ -262,21 +250,18 @@ StyledRect {
if (isChecked) {
if (PluginService.enablePlugin(currentPluginId)) {
ToastService.showInfo("Plugin enabled: " + currentPluginName);
} else {
ToastService.showError("Failed to enable plugin: " + currentPluginName);
checked = false;
}
} else {
if (PluginService.disablePlugin(currentPluginId)) {
ToastService.showInfo("Plugin disabled: " + currentPluginName);
if (root.isExpanded) {
root.expandedPluginId = "";
}
} else {
ToastService.showError("Failed to disable plugin: " + currentPluginName);
checked = true;
return;
}
ToastService.showError("Failed to enable plugin: " + currentPluginName);
return;
}
if (PluginService.disablePlugin(currentPluginId)) {
ToastService.showInfo("Plugin disabled: " + currentPluginName);
if (root.isExpanded)
root.expandedPluginId = "";
return;
}
ToastService.showError("Failed to disable plugin: " + currentPluginName);
}
}
}
@@ -344,7 +329,7 @@ StyledRect {
id: settingsLoader
anchors.fill: parent
anchors.margins: Theme.spacingL
active: root.isExpanded && root.hasSettings && PluginService.isPluginLoaded(root.pluginId)
active: root.isExpanded && root.hasSettings && root.isLoaded
asynchronous: false
source: {
@@ -376,16 +361,10 @@ StyledRect {
StyledText {
anchors.centerIn: parent
text: !PluginService.isPluginLoaded(root.pluginId) ? "Enable plugin to access settings" : (settingsLoader.status === Loader.Error ? "Failed to load settings" : "No configurable settings")
text: !root.isLoaded ? "Enable plugin to access settings" : (settingsLoader.status === Loader.Error ? "Failed to load settings" : "No configurable settings")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
visible: root.isExpanded && (!settingsLoader.active || settingsLoader.status === Loader.Error)
}
}
Loader {
id: tooltipLoader
active: false
sourceComponent: DankTooltip {}
}
}

View File

@@ -11,9 +11,14 @@ FocusScope {
property var parentModal: null
property var installedPluginsData: ({})
property bool isReloading: false
property alias sharedTooltip: sharedTooltip
focus: true
DankTooltipV2 {
id: sharedTooltip
}
DankFlickable {
anchors.fill: parent
clip: true
@@ -124,7 +129,7 @@ FocusScope {
iconName: "store"
enabled: DMSService.dmsAvailable
onClicked: {
pluginBrowserModal.show();
pluginBrowser.show();
}
}
@@ -218,7 +223,7 @@ FocusScope {
Repeater {
id: pluginRepeater
model: PluginService.getAvailablePlugins()
model: PluginService.availablePluginsList
PluginListItem {
pluginData: modelData
@@ -229,6 +234,7 @@ FocusScope {
return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false;
}
isReloading: pluginsTab.isReloading
sharedTooltip: pluginsTab.sharedTooltip
onExpandedPluginIdChanged: {
pluginsTab.expandedPluginId = expandedPluginId;
}
@@ -253,12 +259,7 @@ FocusScope {
}
function refreshPluginList() {
Qt.callLater(() => {
var plugins = PluginService.getAvailablePlugins();
pluginRepeater.model = null;
pluginRepeater.model = plugins;
pluginsTab.isRefreshingPlugins = false;
});
pluginsTab.isRefreshingPlugins = false;
}
Connections {
@@ -286,9 +287,9 @@ FocusScope {
Connections {
target: DMSService
function onPluginsListReceived(plugins) {
pluginBrowserModal.isLoading = false;
pluginBrowserModal.allPlugins = plugins;
pluginBrowserModal.updateFilteredPlugins();
pluginBrowser.isLoading = false;
pluginBrowser.allPlugins = plugins;
pluginBrowser.updateFilteredPlugins();
}
function onInstalledPluginsReceived(plugins) {
var pluginMap = {};
@@ -314,13 +315,12 @@ FocusScope {
}
Component.onCompleted: {
pluginBrowserModal.parentModal = pluginsTab.parentModal;
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8) {
pluginBrowser.parentModal = pluginsTab.parentModal;
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8)
DMSService.listInstalled();
}
}
PluginBrowser {
id: pluginBrowserModal
id: pluginBrowser
}
}

View File

@@ -1,9 +1,9 @@
import QtQuick
import Quickshell
import qs.Common
import qs.Modals.Common
import qs.Widgets
DankModal {
FloatingWindow {
id: root
property var allWidgets: []
@@ -12,7 +12,6 @@ DankModal {
property var filteredWidgets: []
property int selectedIndex: -1
property bool keyboardNavigationActive: false
property Component widgetSelectionContent
property var parentModal: null
signal widgetSelected(string widgetId, string targetSection)
@@ -32,9 +31,8 @@ DankModal {
var description = widget.description ? widget.description.toLowerCase() : "";
var id = widget.id ? widget.id.toLowerCase() : "";
if (text.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) {
if (text.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1)
filtered.push(widget);
}
}
filteredWidgets = filtered;
@@ -58,136 +56,135 @@ DankModal {
return;
keyboardNavigationActive = true;
selectedIndex = Math.max(selectedIndex - 1, -1);
if (selectedIndex === -1) {
if (selectedIndex === -1)
keyboardNavigationActive = false;
}
}
function selectWidget() {
if (selectedIndex >= 0 && selectedIndex < filteredWidgets.length) {
var widget = filteredWidgets[selectedIndex];
root.widgetSelected(widget.id, root.targetSection);
root.close();
}
if (selectedIndex < 0 || selectedIndex >= filteredWidgets.length)
return;
var widget = filteredWidgets[selectedIndex];
root.widgetSelected(widget.id, root.targetSection);
root.hide();
}
function show() {
if (parentModal) {
if (parentModal)
parentModal.shouldHaveFocus = false;
}
open();
visible = true;
Qt.callLater(() => {
if (contentLoader.item && contentLoader.item.searchField) {
contentLoader.item.searchField.forceActiveFocus();
}
searchField.forceActiveFocus();
});
}
function hide() {
close();
if (parentModal) {
parentModal.shouldHaveFocus = Qt.binding(() => {
return parentModal.shouldBeVisible;
});
Qt.callLater(() => {
if (parentModal && parentModal.modalFocusScope) {
parentModal.modalFocusScope.forceActiveFocus();
}
});
}
visible = false;
if (!parentModal)
return;
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
Qt.callLater(() => {
if (parentModal && parentModal.modalFocusScope)
parentModal.modalFocusScope.forceActiveFocus();
});
}
modalWidth: 500
modalHeight: 550
allowStacking: true
backgroundOpacity: 0
closeOnEscapeKey: false
onDialogClosed: () => {
objectName: "widgetSelectionPopup"
title: I18n.tr("Add Widget")
minimumSize: Qt.size(400, 350)
implicitWidth: 500
implicitHeight: 550
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
visible: false
onVisibleChanged: {
if (visible) {
Qt.callLater(() => {
searchField.forceActiveFocus();
});
return;
}
allWidgets = [];
targetSection = "";
searchQuery = "";
filteredWidgets = [];
selectedIndex = -1;
keyboardNavigationActive = false;
if (parentModal) {
parentModal.shouldHaveFocus = Qt.binding(() => {
return parentModal.shouldBeVisible;
});
Qt.callLater(() => {
if (parentModal && parentModal.modalFocusScope) {
parentModal.modalFocusScope.forceActiveFocus();
if (!parentModal)
return;
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
Qt.callLater(() => {
if (parentModal && parentModal.modalFocusScope)
parentModal.modalFocusScope.forceActiveFocus();
});
}
FocusScope {
id: widgetKeyHandler
anchors.fill: parent
focus: true
Keys.onPressed: event => {
switch (event.key) {
case Qt.Key_Escape:
root.hide();
event.accepted = true;
return;
case Qt.Key_Down:
root.selectNext();
event.accepted = true;
return;
case Qt.Key_Up:
root.selectPrevious();
event.accepted = true;
return;
case Qt.Key_Return:
case Qt.Key_Enter:
if (root.keyboardNavigationActive) {
root.selectWidget();
} else if (root.filteredWidgets.length > 0) {
var firstWidget = root.filteredWidgets[0];
root.widgetSelected(firstWidget.id, root.targetSection);
root.hide();
}
});
event.accepted = true;
return;
}
if (event.modifiers & Qt.ControlModifier) {
switch (event.key) {
case Qt.Key_N:
case Qt.Key_J:
root.selectNext();
event.accepted = true;
return;
case Qt.Key_P:
case Qt.Key_K:
root.selectPrevious();
event.accepted = true;
return;
}
}
}
}
onBackgroundClicked: () => {
return hide();
}
content: widgetSelectionContent
widgetSelectionContent: Component {
FocusScope {
id: widgetKeyHandler
property alias searchField: searchField
Column {
anchors.fill: parent
focus: true
spacing: 0
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
root.close();
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
root.selectNext();
event.accepted = true;
} else if (event.key === Qt.Key_Up) {
root.selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
root.selectNext();
event.accepted = true;
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
root.selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
root.selectNext();
event.accepted = true;
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
root.selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (root.keyboardNavigationActive) {
root.selectWidget();
} else if (root.filteredWidgets.length > 0) {
var firstWidget = root.filteredWidgets[0];
root.widgetSelected(firstWidget.id, root.targetSection);
root.close();
}
event.accepted = true;
Item {
id: titleBar
width: parent.width
height: 48
Rectangle {
anchors.fill: parent
color: Theme.surfaceContainer
opacity: 0.5
}
}
DankActionButton {
iconName: "close"
iconSize: Theme.iconSize - 2
iconColor: Theme.outline
anchors.top: parent.top
anchors.topMargin: Theme.spacingM
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
onClicked: root.close()
}
Column {
id: contentColumn
spacing: Theme.spacingM
anchors.fill: parent
anchors.margins: Theme.spacingL
anchors.topMargin: Theme.spacingL + 30 // Space for close button
Row {
width: parent.width
anchors.left: parent.left
anchors.leftMargin: Theme.spacingL
anchors.verticalCenter: parent.verticalCenter
spacing: Theme.spacingM
DankIcon {
@@ -198,134 +195,158 @@ DankModal {
}
StyledText {
text: I18n.tr("Add Widget to ") + root.targetSection + " Section"
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
text: I18n.tr("Add Widget to %1 Section").arg(root.targetSection)
font.pixelSize: Theme.fontSizeXLarge
color: Theme.surfaceText
font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
}
}
StyledText {
text: I18n.tr("Select a widget to add to the ") + root.targetSection.toLowerCase() + " section of the top bar. You can add multiple instances of the same widget if needed."
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width
wrapMode: Text.WordWrap
DankActionButton {
circular: false
iconName: "close"
iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
onClicked: root.hide()
}
}
DankTextField {
id: searchField
width: parent.width
height: 48
cornerRadius: Theme.cornerRadius
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
normalBorderColor: Theme.outlineMedium
focusedBorderColor: Theme.primary
leftIconName: "search"
leftIconSize: Theme.iconSize
leftIconColor: Theme.surfaceVariantText
leftIconFocusedColor: Theme.primary
showClearButton: true
textColor: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
placeholderText: ""
text: root.searchQuery
focus: true
ignoreLeftRightKeys: true
keyForwardTargets: [widgetKeyHandler]
onTextEdited: {
root.searchQuery = text;
updateFilteredWidgets();
Item {
width: parent.width
height: parent.height - titleBar.height
Column {
id: contentColumn
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
StyledText {
text: I18n.tr("Select a widget to add. You can add multiple instances of the same widget if needed.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
width: parent.width
wrapMode: Text.WordWrap
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
root.close();
event.accepted = true;
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
event.accepted = false;
DankTextField {
id: searchField
width: parent.width
height: 48
cornerRadius: Theme.cornerRadius
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
normalBorderColor: Theme.outlineMedium
focusedBorderColor: Theme.primary
leftIconName: "search"
leftIconSize: Theme.iconSize
leftIconColor: Theme.surfaceVariantText
leftIconFocusedColor: Theme.primary
showClearButton: true
textColor: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium
placeholderText: I18n.tr("Search widgets...")
text: root.searchQuery
focus: true
ignoreLeftRightKeys: true
keyForwardTargets: [widgetKeyHandler]
onTextEdited: {
root.searchQuery = text;
updateFilteredWidgets();
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Escape) {
root.hide();
event.accepted = true;
return;
}
if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0))
event.accepted = false;
}
}
}
DankListView {
id: widgetList
DankListView {
id: widgetList
width: parent.width
height: parent.height - y
spacing: Theme.spacingS
model: root.filteredWidgets
clip: true
width: parent.width
height: parent.height - y
spacing: Theme.spacingS
model: root.filteredWidgets
clip: true
delegate: Rectangle {
width: widgetList.width
height: 60
radius: Theme.cornerRadius
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: isSelected ? 2 : 1
delegate: Rectangle {
width: widgetList.width
height: 60
radius: Theme.cornerRadius
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
border.width: isSelected ? 2 : 1
Row {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
Row {
anchors.fill: parent
anchors.margins: Theme.spacingM
spacing: Theme.spacingM
DankIcon {
name: modelData.icon
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - Theme.iconSize - Theme.spacingM * 3
StyledText {
text: modelData.text
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
elide: Text.ElideRight
width: parent.width
DankIcon {
name: modelData.icon
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: modelData.description
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
elide: Text.ElideRight
width: parent.width
wrapMode: Text.WordWrap
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 2
width: parent.width - Theme.iconSize - Theme.spacingM * 3
StyledText {
text: modelData.text
font.pixelSize: Theme.fontSizeMedium
font.weight: Font.Medium
color: Theme.surfaceText
elide: Text.ElideRight
width: parent.width
}
StyledText {
text: modelData.description
font.pixelSize: Theme.fontSizeSmall
color: Theme.outline
elide: Text.ElideRight
width: parent.width
wrapMode: Text.WordWrap
}
}
DankIcon {
name: "add"
size: Theme.iconSize - 4
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
}
DankIcon {
name: "add"
size: Theme.iconSize - 4
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
MouseArea {
id: widgetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.widgetSelected(modelData.id, root.targetSection);
root.hide();
}
}
}
MouseArea {
id: widgetArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.widgetSelected(modelData.id, root.targetSection);
root.close();
}
}
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
Behavior on color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}
}

View File

@@ -682,7 +682,7 @@ Item {
anchors.verticalCenter: parent.verticalCenter
checked: SettingsData.osdAlwaysShowValue
onToggleCompleted: checked => {
onToggled: checked => {
SettingsData.set("osdAlwaysShowValue", checked);
}
}

View File

@@ -11,48 +11,65 @@ Scope {
property bool searchActive: false
property string searchActiveScreen: ""
property bool overlayActive: NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)
property bool isClosing: false
property bool overlayActive: (NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)) || searchActive
function showSpotlight(screenName) {
searchActive = true
searchActiveScreen = screenName
isClosing = false;
searchActive = true;
searchActiveScreen = screenName;
}
function hideSpotlight() {
searchActive = false
searchActiveScreen = ""
if (!searchActive)
return;
isClosing = true;
}
function completeHide() {
searchActive = false;
searchActiveScreen = "";
isClosing = false;
}
Connections {
target: NiriService
function onInOverviewChanged() {
if (!NiriService.inOverview) {
hideSpotlight()
} else {
searchActive = false
searchActiveScreen = ""
if (searchActive) {
isClosing = true;
return;
}
closeOverviewAfterAnim = false;
searchActive = false;
searchActiveScreen = "";
isClosing = false;
return;
}
searchActive = false;
searchActiveScreen = "";
isClosing = false;
}
function onCurrentOutputChanged() {
if (NiriService.inOverview && searchActive && searchActiveScreen !== "" && searchActiveScreen !== NiriService.currentOutput) {
hideSpotlight()
}
if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput)
return;
hideSpotlight();
}
}
Connections {
target: PopoutService.spotlightModal
function onSpotlightOpenChanged() {
if (PopoutService.spotlightModal?.spotlightOpen && searchActive) {
hideSpotlight()
}
if (!PopoutService.spotlightModal?.spotlightOpen || !searchActive)
return;
hideSpotlight();
}
}
Loader {
id: niriOverlayLoader
active: overlayActive
active: overlayActive || isClosing
asynchronous: false
sourceComponent: Variants {
@@ -65,29 +82,34 @@ Scope {
readonly property real dpr: CompositorService.getScreenScale(screen)
readonly property bool isActiveScreen: screen.name === NiriService.currentOutput
readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen
readonly property bool shouldShowSpotlight: niriOverviewScope.searchActive && screen.name === niriOverviewScope.searchActiveScreen && !niriOverviewScope.isClosing
readonly property bool isSpotlightScreen: screen.name === niriOverviewScope.searchActiveScreen
screen: modelData
visible: NiriService.inOverview
visible: NiriService.inOverview || niriOverviewScope.isClosing
color: "transparent"
WlrLayershell.namespace: "dms:niri-overview-spotlight"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: {
if (!NiriService.inOverview) return WlrKeyboardFocus.None
if (!isActiveScreen) return WlrKeyboardFocus.None
return WlrKeyboardFocus.Exclusive
if (!NiriService.inOverview)
return WlrKeyboardFocus.None;
if (!isActiveScreen)
return WlrKeyboardFocus.None;
if (niriOverviewScope.isClosing)
return WlrKeyboardFocus.None;
return WlrKeyboardFocus.Exclusive;
}
mask: Region {
item: shouldShowSpotlight ? spotlightContainer : null
item: spotlightContainer.visible ? spotlightContainer : null
}
onShouldShowSpotlightChanged: {
if (!shouldShowSpotlight && isActiveScreen) {
Qt.callLater(() => keyboardFocusScope.forceActiveFocus())
}
if (shouldShowSpotlight || !isActiveScreen)
return;
Qt.callLater(() => keyboardFocusScope.forceActiveFocus());
}
anchors {
@@ -97,61 +119,62 @@ Scope {
bottom: true
}
FocusScope {
id: keyboardFocusScope
anchors.fill: parent
focus: true
Keys.onPressed: event => {
if (!overlayWindow.shouldShowSpotlight) {
if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) {
NiriService.toggleOverview()
event.accepted = true
return
}
if (event.key === Qt.Key_Left) {
NiriService.moveColumnLeft()
event.accepted = true
return
}
if (event.key === Qt.Key_Right) {
NiriService.moveColumnRight()
event.accepted = true
return
}
if (event.key === Qt.Key_Up) {
NiriService.moveWorkspaceUp()
event.accepted = true
return
}
if (event.key === Qt.Key_Down) {
NiriService.moveWorkspaceDown()
event.accepted = true
return
}
if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) {
event.accepted = false
return
}
if (!event.isAutoRepeat && event.text) {
niriOverviewScope.showSpotlight(overlayWindow.screen.name)
if (spotlightContent?.searchField) {
spotlightContent.searchField.text = event.text.trim()
if (spotlightContent.appLauncher) {
spotlightContent.appLauncher.searchQuery = event.text.trim()
}
Qt.callLater(() => spotlightContent.searchField.forceActiveFocus())
}
event.accepted = true
}
if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing)
return;
if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) {
NiriService.toggleOverview();
event.accepted = true;
return;
}
if (event.key === Qt.Key_Left) {
NiriService.moveColumnLeft();
event.accepted = true;
return;
}
if (event.key === Qt.Key_Right) {
NiriService.moveColumnRight();
event.accepted = true;
return;
}
if (event.key === Qt.Key_Up) {
NiriService.moveWorkspaceUp();
event.accepted = true;
return;
}
if (event.key === Qt.Key_Down) {
NiriService.moveWorkspaceDown();
event.accepted = true;
return;
}
if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) {
event.accepted = false;
return;
}
if (event.isAutoRepeat || !event.text)
return;
if (!spotlightContent?.searchField)
return;
const trimmedText = event.text.trim();
spotlightContainer.waitingForResults = true;
spotlightContent.searchField.text = trimmedText;
if (spotlightContent.appLauncher) {
spotlightContent.appLauncher.searchQuery = trimmedText;
}
niriOverviewScope.showSpotlight(overlayWindow.screen.name);
Qt.callLater(() => spotlightContent.searchField.forceActiveFocus());
event.accepted = true;
}
}
@@ -162,28 +185,35 @@ Scope {
width: Theme.px(500, overlayWindow.dpr)
height: Theme.px(600, overlayWindow.dpr)
property real scaleValue: 0.96
readonly property bool animatingOut: niriOverviewScope.isClosing && overlayWindow.isSpotlightScreen
property bool waitingForResults: false
scale: scaleValue
opacity: overlayWindow.shouldShowSpotlight ? 1 : 0
Connections {
target: spotlightContent.appLauncher?.model ?? null
function onCountChanged() {
spotlightContainer.waitingForResults = false;
}
}
scale: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1.0 : 0.96
opacity: (overlayWindow.shouldShowSpotlight && !waitingForResults) ? 1 : 0
visible: (overlayWindow.shouldShowSpotlight && !waitingForResults) || animatingOut
enabled: overlayWindow.shouldShowSpotlight
layer.enabled: true
layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr))
Connections {
target: overlayWindow
function onShouldShowSpotlightChanged() {
spotlightContainer.scaleValue = overlayWindow.shouldShowSpotlight ? 1.0 : 0.96
}
}
Behavior on scaleValue {
Behavior on scale {
NumberAnimation {
duration: Theme.expressiveDurations.expressiveDefaultSpatial
easing.type: Easing.BezierSpline
easing.bezierCurve: niriOverviewScope.searchActive ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
onRunningChanged: {
if (running || !spotlightContainer.animatingOut)
return;
niriOverviewScope.completeHide();
}
}
}
@@ -191,7 +221,7 @@ Scope {
NumberAnimation {
duration: Theme.expressiveDurations.expressiveDefaultSpatial
easing.type: Easing.BezierSpline
easing.bezierCurve: niriOverviewScope.searchActive ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
easing.bezierCurve: spotlightContainer.visible ? Theme.expressiveCurves.expressiveDefaultSpatial : Theme.expressiveCurves.emphasized
}
}
@@ -209,17 +239,14 @@ Scope {
anchors.margins: 0
property var fakeParentModal: QtObject {
property bool spotlightOpen: overlayWindow.shouldShowSpotlight
property bool spotlightOpen: spotlightContainer.visible
function hide() {
niriOverviewScope.hideSpotlight()
if (overlayWindow.isActiveScreen) {
Qt.callLater(() => keyboardFocusScope.forceActiveFocus())
}
niriOverviewScope.hideSpotlight();
}
}
Component.onCompleted: {
parentModal = fakeParentModal
parentModal = fakeParentModal;
}
}
}

View File

@@ -1,12 +1,10 @@
pragma Singleton
pragma ComponentBehavior: Bound
import QtCore
import QtQuick
import Qt.labs.folderlistmodel
import Quickshell
import Quickshell.Io
import qs.Common
Singleton {
@@ -17,13 +15,14 @@ Singleton {
property var pluginWidgetComponents: ({})
property var pluginDaemonComponents: ({})
property var pluginLauncherComponents: ({})
property var availablePluginsList: []
property string pluginDirectory: {
var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation)
var configDirStr = configDir.toString()
var configDir = StandardPaths.writableLocation(StandardPaths.ConfigLocation);
var configDirStr = configDir.toString();
if (configDirStr.startsWith("file://")) {
configDirStr = configDirStr.substring(7)
configDirStr = configDirStr.substring(7);
}
return configDirStr + "/DankMaterialShell/plugins"
return configDirStr + "/DankMaterialShell/plugins";
}
property string systemPluginDirectory: "/etc/xdg/quickshell/dms-plugins"
@@ -36,7 +35,7 @@ Singleton {
signal pluginUnloaded(string pluginId)
signal pluginLoadFailed(string pluginId, string error)
signal pluginDataChanged(string pluginId)
signal pluginListUpdated()
signal pluginListUpdated
signal globalVarChanged(string pluginId, string varName)
Timer {
@@ -47,9 +46,9 @@ Singleton {
}
Component.onCompleted: {
userWatcher.folder = Paths.toFileUrl(root.pluginDirectory)
systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory)
Qt.callLater(resyncAll)
userWatcher.folder = Paths.toFileUrl(root.pluginDirectory);
systemWatcher.folder = Paths.toFileUrl(root.systemPluginDirectory);
Qt.callLater(resyncAll);
}
FolderListModel {
@@ -57,10 +56,12 @@ Singleton {
showDirs: true
showFiles: false
showDotAndDotDot: false
nameFilters: ["plugin.json"]
onCountChanged: resyncDebounce.restart()
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
onStatusChanged: {
if (status === FolderListModel.Ready)
resyncDebounce.restart();
}
}
FolderListModel {
@@ -68,65 +69,74 @@ Singleton {
showDirs: true
showFiles: false
showDotAndDotDot: false
nameFilters: ["plugin.json"]
onCountChanged: resyncDebounce.restart()
onStatusChanged: if (status === FolderListModel.Ready) resyncDebounce.restart()
onStatusChanged: {
if (status === FolderListModel.Ready)
resyncDebounce.restart();
}
}
function snapshotModel(model, sourceTag) {
const out = []
const n = model.count
const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory
const out = [];
const n = model.count;
const baseDir = sourceTag === "user" ? pluginDirectory : systemPluginDirectory;
for (let i = 0; i < n; i++) {
let dirPath = model.get(i, "filePath")
let dirPath = model.get(i, "filePath");
if (dirPath.startsWith("file://")) {
dirPath = dirPath.substring(7)
dirPath = dirPath.substring(7);
}
if (!dirPath.startsWith(baseDir)) {
continue
continue;
}
const manifestPath = dirPath + "/plugin.json"
out.push({ path: manifestPath, source: sourceTag })
const manifestPath = dirPath + "/plugin.json";
out.push({
path: manifestPath,
source: sourceTag
});
}
return out
return out;
}
function resyncAll() {
const userList = snapshotModel(userWatcher, "user")
const sysList = snapshotModel(systemWatcher, "system")
const seenPaths = {}
const userList = snapshotModel(userWatcher, "user");
const sysList = snapshotModel(systemWatcher, "system");
const seenPaths = {};
function consider(entry) {
const key = entry.path
seenPaths[key] = true
const prev = knownManifests[key]
const key = entry.path;
seenPaths[key] = true;
const prev = knownManifests[key];
if (!prev) {
loadPluginManifestFile(entry.path, entry.source, Date.now())
loadPluginManifestFile(entry.path, entry.source, Date.now());
}
}
for (let i=0;i<userList.length;i++) consider(userList[i])
for (let i=0;i<sysList.length;i++) consider(sysList[i])
for (let i = 0; i < userList.length; i++)
consider(userList[i]);
for (let i = 0; i < sysList.length; i++)
consider(sysList[i]);
const removed = []
const removed = [];
for (const path in knownManifests) {
if (!seenPaths[path]) removed.push(path)
if (!seenPaths[path])
removed.push(path);
}
if (removed.length) {
removed.forEach(function(path) {
const pid = pathToPluginId[path]
removed.forEach(function (path) {
const pid = pathToPluginId[path];
if (pid) {
unregisterPluginByPath(path, pid)
unregisterPluginByPath(path, pid);
}
delete knownManifests[path]
delete pathToPluginId[path]
})
pluginListUpdated()
delete knownManifests[path];
delete pathToPluginId[path];
});
_updateAvailablePluginsList();
pluginListUpdated();
}
}
function loadPluginManifestFile(manifestPathNoScheme, sourceTag, mtimeEpochMs) {
const manifestId = "m_" + Math.random().toString(36).slice(2)
const manifestId = "m_" + Math.random().toString(36).slice(2);
const qml = `
import QtQuick
import Quickshell.Io
@@ -150,226 +160,251 @@ Singleton {
fv.destroy()
}
}
`
const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId)
loader.absPath = manifestPathNoScheme
loader.path = manifestPathNoScheme
`;
const loader = Qt.createQmlObject(qml, root, "mf_" + manifestId);
loader.absPath = manifestPathNoScheme;
loader.path = manifestPathNoScheme;
}
function _onManifestParsed(absPath, manifest, sourceTag, mtimeEpochMs) {
if (!manifest || !manifest.id || !manifest.name || !manifest.component) {
console.error("PluginService: invalid manifest fields:", absPath)
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, bad: true }
return
console.error("PluginService: invalid manifest fields:", absPath);
knownManifests[absPath] = {
mtime: mtimeEpochMs,
source: sourceTag,
bad: true
};
return;
}
const dir = absPath.substring(0, absPath.lastIndexOf('/'))
let comp = manifest.component
if (comp.startsWith("./")) comp = comp.slice(2)
let settings = manifest.settings
if (settings && settings.startsWith("./")) settings = settings.slice(2)
const dir = absPath.substring(0, absPath.lastIndexOf('/'));
let comp = manifest.component;
if (comp.startsWith("./"))
comp = comp.slice(2);
let settings = manifest.settings;
if (settings && settings.startsWith("./"))
settings = settings.slice(2);
const info = {}
for (const k in manifest) info[k] = manifest[k]
const info = {};
for (const k in manifest)
info[k] = manifest[k];
let perms = manifest.permissions
let perms = manifest.permissions;
if (typeof perms === "string") {
perms = perms.split(/\s*,\s*/)
perms = perms.split(/\s*,\s*/);
}
if (!Array.isArray(perms)) {
perms = []
perms = [];
}
info.permissions = perms.map(p => String(p).trim())
info.permissions = perms.map(p => String(p).trim());
info.manifestPath = absPath
info.pluginDirectory = dir
info.componentPath = dir + "/" + comp
info.settingsPath = settings ? (dir + "/" + settings) : null
info.loaded = isPluginLoaded(manifest.id)
info.type = manifest.type || "widget"
info.source = sourceTag
info.manifestPath = absPath;
info.pluginDirectory = dir;
info.componentPath = dir + "/" + comp;
info.settingsPath = settings ? (dir + "/" + settings) : null;
info.loaded = isPluginLoaded(manifest.id);
info.type = manifest.type || "widget";
info.source = sourceTag;
const existing = availablePlugins[manifest.id]
const shouldReplace =
(!existing) ||
(existing && existing.source === "system" && sourceTag === "user")
const existing = availablePlugins[manifest.id];
const shouldReplace = (!existing) || (existing && existing.source === "system" && sourceTag === "user");
if (shouldReplace) {
if (existing && existing.loaded && existing.source !== sourceTag) {
unloadPlugin(manifest.id)
unloadPlugin(manifest.id);
}
const newMap = Object.assign({}, availablePlugins)
newMap[manifest.id] = info
availablePlugins = newMap
pathToPluginId[absPath] = manifest.id
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag }
pluginListUpdated()
const enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false)
if (enabled && !info.loaded) loadPlugin(manifest.id)
const newMap = Object.assign({}, availablePlugins);
newMap[manifest.id] = info;
availablePlugins = newMap;
pathToPluginId[absPath] = manifest.id;
knownManifests[absPath] = {
mtime: mtimeEpochMs,
source: sourceTag
};
_updateAvailablePluginsList();
pluginListUpdated();
const enabled = SettingsData.getPluginSetting(manifest.id, "enabled", false);
if (enabled && !info.loaded)
loadPlugin(manifest.id);
} else {
knownManifests[absPath] = { mtime: mtimeEpochMs, source: sourceTag, shadowedBy: existing.source }
pathToPluginId[absPath] = manifest.id
knownManifests[absPath] = {
mtime: mtimeEpochMs,
source: sourceTag,
shadowedBy: existing.source
};
pathToPluginId[absPath] = manifest.id;
}
}
function unregisterPluginByPath(absPath, pluginId) {
const current = availablePlugins[pluginId]
const current = availablePlugins[pluginId];
if (current && current.manifestPath === absPath) {
if (current.loaded) unloadPlugin(pluginId)
const newMap = Object.assign({}, availablePlugins)
delete newMap[pluginId]
availablePlugins = newMap
if (current.loaded)
unloadPlugin(pluginId);
const newMap = Object.assign({}, availablePlugins);
delete newMap[pluginId];
availablePlugins = newMap;
}
}
function loadPlugin(pluginId) {
const plugin = availablePlugins[pluginId]
function loadPlugin(pluginId, bustCache) {
const plugin = availablePlugins[pluginId];
if (!plugin) {
console.error("PluginService: Plugin not found:", pluginId)
pluginLoadFailed(pluginId, "Plugin not found")
return false
console.error("PluginService: Plugin not found:", pluginId);
pluginLoadFailed(pluginId, "Plugin not found");
return false;
}
if (plugin.loaded) {
return true
return true;
}
const isDaemon = plugin.type === "daemon"
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"))
const map = isDaemon ? pluginDaemonComponents : isLauncher ? pluginLauncherComponents : pluginWidgetComponents
const isDaemon = plugin.type === "daemon";
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
const prevInstance = pluginInstances[pluginId]
const prevInstance = pluginInstances[pluginId];
if (prevInstance) {
prevInstance.destroy()
const newInstances = Object.assign({}, pluginInstances)
delete newInstances[pluginId]
pluginInstances = newInstances
prevInstance.destroy();
const newInstances = Object.assign({}, pluginInstances);
delete newInstances[pluginId];
pluginInstances = newInstances;
}
try {
const url = "file://" + plugin.componentPath
const comp = Qt.createComponent(url, Component.PreferSynchronous)
let url = "file://" + plugin.componentPath;
if (bustCache)
url += "?t=" + Date.now();
const comp = Qt.createComponent(url, Component.PreferSynchronous);
if (comp.status === Component.Error) {
console.error("PluginService: component error", pluginId, comp.errorString())
pluginLoadFailed(pluginId, comp.errorString())
return false
console.error("PluginService: component error", pluginId, comp.errorString());
pluginLoadFailed(pluginId, comp.errorString());
return false;
}
if (isDaemon) {
const instance = comp.createObject(root, { "pluginId": pluginId })
const instance = comp.createObject(root, {
"pluginId": pluginId
});
if (!instance) {
console.error("PluginService: failed to instantiate daemon:", pluginId, comp.errorString())
pluginLoadFailed(pluginId, comp.errorString())
return false
console.error("PluginService: failed to instantiate daemon:", pluginId, comp.errorString());
pluginLoadFailed(pluginId, comp.errorString());
return false;
}
const newInstances = Object.assign({}, pluginInstances)
newInstances[pluginId] = instance
pluginInstances = newInstances
const newInstances = Object.assign({}, pluginInstances);
newInstances[pluginId] = instance;
pluginInstances = newInstances;
const newDaemons = Object.assign({}, pluginDaemonComponents)
newDaemons[pluginId] = comp
pluginDaemonComponents = newDaemons
const newDaemons = Object.assign({}, pluginDaemonComponents);
newDaemons[pluginId] = comp;
pluginDaemonComponents = newDaemons;
} else if (isLauncher) {
const newLaunchers = Object.assign({}, pluginLauncherComponents)
newLaunchers[pluginId] = comp
pluginLauncherComponents = newLaunchers
const newLaunchers = Object.assign({}, pluginLauncherComponents);
newLaunchers[pluginId] = comp;
pluginLauncherComponents = newLaunchers;
} else {
const newComponents = Object.assign({}, pluginWidgetComponents)
newComponents[pluginId] = comp
pluginWidgetComponents = newComponents
const newComponents = Object.assign({}, pluginWidgetComponents);
newComponents[pluginId] = comp;
pluginWidgetComponents = newComponents;
}
plugin.loaded = true
loadedPlugins[pluginId] = plugin
pluginLoaded(pluginId)
return true
plugin.loaded = true;
const newLoaded = Object.assign({}, loadedPlugins);
newLoaded[pluginId] = plugin;
loadedPlugins = newLoaded;
pluginLoaded(pluginId);
return true;
} catch (e) {
console.error("PluginService: Error loading plugin:", pluginId, e.message)
pluginLoadFailed(pluginId, e.message)
return false
console.error("PluginService: Error loading plugin:", pluginId, e.message);
pluginLoadFailed(pluginId, e.message);
return false;
}
}
function unloadPlugin(pluginId) {
const plugin = loadedPlugins[pluginId]
const plugin = loadedPlugins[pluginId];
if (!plugin) {
console.warn("PluginService: Plugin not loaded:", pluginId)
return false
console.warn("PluginService: Plugin not loaded:", pluginId);
return false;
}
try {
const isDaemon = plugin.type === "daemon"
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"))
const isDaemon = plugin.type === "daemon";
const isLauncher = plugin.type === "launcher" || (plugin.capabilities && plugin.capabilities.includes("launcher"));
const instance = pluginInstances[pluginId]
const instance = pluginInstances[pluginId];
if (instance) {
instance.destroy()
const newInstances = Object.assign({}, pluginInstances)
delete newInstances[pluginId]
pluginInstances = newInstances
instance.destroy();
const newInstances = Object.assign({}, pluginInstances);
delete newInstances[pluginId];
pluginInstances = newInstances;
}
if (isDaemon && pluginDaemonComponents[pluginId]) {
const newDaemons = Object.assign({}, pluginDaemonComponents)
delete newDaemons[pluginId]
pluginDaemonComponents = newDaemons
const newDaemons = Object.assign({}, pluginDaemonComponents);
delete newDaemons[pluginId];
pluginDaemonComponents = newDaemons;
} else if (isLauncher && pluginLauncherComponents[pluginId]) {
const newLaunchers = Object.assign({}, pluginLauncherComponents)
delete newLaunchers[pluginId]
pluginLauncherComponents = newLaunchers
const newLaunchers = Object.assign({}, pluginLauncherComponents);
delete newLaunchers[pluginId];
pluginLauncherComponents = newLaunchers;
} else if (pluginWidgetComponents[pluginId]) {
const newComponents = Object.assign({}, pluginWidgetComponents)
delete newComponents[pluginId]
pluginWidgetComponents = newComponents
const newComponents = Object.assign({}, pluginWidgetComponents);
delete newComponents[pluginId];
pluginWidgetComponents = newComponents;
}
plugin.loaded = false
delete loadedPlugins[pluginId]
pluginUnloaded(pluginId)
return true
plugin.loaded = false;
const newLoaded = Object.assign({}, loadedPlugins);
delete newLoaded[pluginId];
loadedPlugins = newLoaded;
pluginUnloaded(pluginId);
return true;
} catch (error) {
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message)
return false
console.error("PluginService: Error unloading plugin:", pluginId, "Error:", error.message);
return false;
}
}
function getWidgetComponents() {
return pluginWidgetComponents
return pluginWidgetComponents;
}
function getDaemonComponents() {
return pluginDaemonComponents
return pluginDaemonComponents;
}
function getAvailablePlugins() {
const result = []
return availablePluginsList;
}
function _updateAvailablePluginsList() {
const result = [];
for (const key in availablePlugins) {
result.push(availablePlugins[key])
result.push(availablePlugins[key]);
}
return result
availablePluginsList = result;
}
function getPluginVariants(pluginId) {
const plugin = availablePlugins[pluginId]
const plugin = availablePlugins[pluginId];
if (!plugin) {
return []
return [];
}
const variants = SettingsData.getPluginSetting(pluginId, "variants", [])
return variants
const variants = SettingsData.getPluginSetting(pluginId, "variants", []);
return variants;
}
function getAllPluginVariants() {
const result = []
const result = [];
for (const pluginId in availablePlugins) {
const plugin = availablePlugins[pluginId]
const plugin = availablePlugins[pluginId];
if (plugin.type !== "widget") {
continue
continue;
}
const variants = getPluginVariants(pluginId)
const variants = getPluginVariants(pluginId);
if (variants.length === 0) {
result.push({
pluginId: pluginId,
@@ -379,10 +414,10 @@ Singleton {
icon: plugin.icon || "extension",
description: plugin.description || "Plugin widget",
loaded: plugin.loaded
})
});
} else {
for (let i = 0; i < variants.length; i++) {
const variant = variants[i]
const variant = variants[i];
result.push({
pluginId: pluginId,
variantId: variant.id,
@@ -391,244 +426,245 @@ Singleton {
icon: variant.icon || plugin.icon || "extension",
description: variant.description || plugin.description || "Plugin widget variant",
loaded: plugin.loaded
})
});
}
}
}
return result
return result;
}
function createPluginVariant(pluginId, variantName, variantConfig) {
const variants = getPluginVariants(pluginId)
const variantId = "variant_" + Date.now()
const variants = getPluginVariants(pluginId);
const variantId = "variant_" + Date.now();
const newVariant = Object.assign({}, variantConfig, {
id: variantId,
name: variantName
})
variants.push(newVariant)
SettingsData.setPluginSetting(pluginId, "variants", variants)
pluginDataChanged(pluginId)
return variantId
});
variants.push(newVariant);
SettingsData.setPluginSetting(pluginId, "variants", variants);
pluginDataChanged(pluginId);
return variantId;
}
function removePluginVariant(pluginId, variantId) {
const variants = getPluginVariants(pluginId)
const newVariants = variants.filter(function(v) { return v.id !== variantId })
SettingsData.setPluginSetting(pluginId, "variants", newVariants)
const variants = getPluginVariants(pluginId);
const newVariants = variants.filter(function (v) {
return v.id !== variantId;
});
SettingsData.setPluginSetting(pluginId, "variants", newVariants);
const fullId = pluginId + ":" + variantId
removeWidgetFromDankBar(fullId)
const fullId = pluginId + ":" + variantId;
removeWidgetFromDankBar(fullId);
pluginDataChanged(pluginId)
pluginDataChanged(pluginId);
}
function removeWidgetFromDankBar(widgetId) {
function filterWidget(widget) {
const id = typeof widget === "string" ? widget : widget.id
return id !== widgetId
const id = typeof widget === "string" ? widget : widget.id;
return id !== widgetId;
}
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
if (!defaultBar) return
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
if (!defaultBar)
return;
const leftWidgets = defaultBar.leftWidgets || [];
const centerWidgets = defaultBar.centerWidgets || [];
const rightWidgets = defaultBar.rightWidgets || [];
const leftWidgets = defaultBar.leftWidgets || []
const centerWidgets = defaultBar.centerWidgets || []
const rightWidgets = defaultBar.rightWidgets || []
const newLeft = leftWidgets.filter(filterWidget)
const newCenter = centerWidgets.filter(filterWidget)
const newRight = rightWidgets.filter(filterWidget)
const newLeft = leftWidgets.filter(filterWidget);
const newCenter = centerWidgets.filter(filterWidget);
const newRight = rightWidgets.filter(filterWidget);
if (newLeft.length !== leftWidgets.length) {
SettingsData.setDankBarLeftWidgets(newLeft)
SettingsData.setDankBarLeftWidgets(newLeft);
}
if (newCenter.length !== centerWidgets.length) {
SettingsData.setDankBarCenterWidgets(newCenter)
SettingsData.setDankBarCenterWidgets(newCenter);
}
if (newRight.length !== rightWidgets.length) {
SettingsData.setDankBarRightWidgets(newRight)
SettingsData.setDankBarRightWidgets(newRight);
}
}
function updatePluginVariant(pluginId, variantId, variantConfig) {
const variants = getPluginVariants(pluginId)
const variants = getPluginVariants(pluginId);
for (let i = 0; i < variants.length; i++) {
if (variants[i].id === variantId) {
variants[i] = Object.assign({}, variants[i], variantConfig)
break
variants[i] = Object.assign({}, variants[i], variantConfig);
break;
}
}
SettingsData.setPluginSetting(pluginId, "variants", variants)
pluginDataChanged(pluginId)
SettingsData.setPluginSetting(pluginId, "variants", variants);
pluginDataChanged(pluginId);
}
function getPluginVariantData(pluginId, variantId) {
const variants = getPluginVariants(pluginId)
const variants = getPluginVariants(pluginId);
for (let i = 0; i < variants.length; i++) {
if (variants[i].id === variantId) {
return variants[i]
return variants[i];
}
}
return null
return null;
}
function getLoadedPlugins() {
const result = []
const result = [];
for (const key in loadedPlugins) {
result.push(loadedPlugins[key])
result.push(loadedPlugins[key]);
}
return result
return result;
}
function isPluginLoaded(pluginId) {
return loadedPlugins[pluginId] !== undefined
return loadedPlugins[pluginId] !== undefined;
}
function enablePlugin(pluginId) {
SettingsData.setPluginSetting(pluginId, "enabled", true)
return loadPlugin(pluginId)
SettingsData.setPluginSetting(pluginId, "enabled", true);
return loadPlugin(pluginId);
}
function disablePlugin(pluginId) {
SettingsData.setPluginSetting(pluginId, "enabled", false)
return unloadPlugin(pluginId)
SettingsData.setPluginSetting(pluginId, "enabled", false);
return unloadPlugin(pluginId);
}
function reloadPlugin(pluginId) {
if (isPluginLoaded(pluginId)) {
unloadPlugin(pluginId)
}
return loadPlugin(pluginId)
if (isPluginLoaded(pluginId))
unloadPlugin(pluginId);
return loadPlugin(pluginId, true);
}
function savePluginData(pluginId, key, value) {
SettingsData.setPluginSetting(pluginId, key, value)
pluginDataChanged(pluginId)
return true
SettingsData.setPluginSetting(pluginId, key, value);
pluginDataChanged(pluginId);
return true;
}
function loadPluginData(pluginId, key, defaultValue) {
return SettingsData.getPluginSetting(pluginId, key, defaultValue)
return SettingsData.getPluginSetting(pluginId, key, defaultValue);
}
function saveAllPluginSettings() {
SettingsData.savePluginSettings()
SettingsData.savePluginSettings();
}
function scanPlugins() {
resyncDebounce.restart()
resyncDebounce.restart();
}
function forceRescanPlugin(pluginId) {
const plugin = availablePlugins[pluginId]
const plugin = availablePlugins[pluginId];
if (plugin && plugin.manifestPath) {
const manifestPath = plugin.manifestPath
const source = plugin.source || "user"
delete knownManifests[manifestPath]
const newMap = Object.assign({}, availablePlugins)
delete newMap[pluginId]
availablePlugins = newMap
loadPluginManifestFile(manifestPath, source, Date.now())
const manifestPath = plugin.manifestPath;
const source = plugin.source || "user";
delete knownManifests[manifestPath];
const newMap = Object.assign({}, availablePlugins);
delete newMap[pluginId];
availablePlugins = newMap;
loadPluginManifestFile(manifestPath, source, Date.now());
}
}
function createPluginDirectory() {
const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }")
const mkdirProcess = Qt.createComponent("data:text/plain,import Quickshell.Io; Process { }");
if (mkdirProcess.status === Component.Ready) {
const process = mkdirProcess.createObject(root)
process.command = ["mkdir", "-p", pluginDirectory]
process.exited.connect(function(exitCode) {
const process = mkdirProcess.createObject(root);
process.command = ["mkdir", "-p", pluginDirectory];
process.exited.connect(function (exitCode) {
if (exitCode !== 0) {
console.error("PluginService: Failed to create plugin directory, exit code:", exitCode)
console.error("PluginService: Failed to create plugin directory, exit code:", exitCode);
}
process.destroy()
})
process.running = true
return true
process.destroy();
});
process.running = true;
return true;
} else {
console.error("PluginService: Failed to create mkdir process")
return false
console.error("PluginService: Failed to create mkdir process");
return false;
}
}
// Launcher plugin helper functions
function getLauncherPlugins() {
const launchers = {}
const launchers = {};
// Check plugins that have launcher components
for (const pluginId in pluginLauncherComponents) {
const plugin = availablePlugins[pluginId]
const plugin = availablePlugins[pluginId];
if (plugin && plugin.loaded) {
launchers[pluginId] = plugin
launchers[pluginId] = plugin;
}
}
return launchers
return launchers;
}
function getLauncherPlugin(pluginId) {
const plugin = availablePlugins[pluginId]
const plugin = availablePlugins[pluginId];
if (plugin && plugin.loaded && pluginLauncherComponents[pluginId]) {
return plugin
return plugin;
}
return null
return null;
}
function getPluginTrigger(pluginId) {
const plugin = getLauncherPlugin(pluginId)
const plugin = getLauncherPlugin(pluginId);
if (plugin) {
// Check if noTrigger is set (always active mode)
const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false)
const noTrigger = SettingsData.getPluginSetting(pluginId, "noTrigger", false);
if (noTrigger) {
return ""
return "";
}
// Otherwise load the custom trigger, defaulting to plugin manifest trigger
const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!")
return customTrigger
const customTrigger = SettingsData.getPluginSetting(pluginId, "trigger", plugin.trigger || "!");
return customTrigger;
}
return null
return null;
}
function getAllPluginTriggers() {
const triggers = {}
const launchers = getLauncherPlugins()
const triggers = {};
const launchers = getLauncherPlugins();
for (const pluginId in launchers) {
const trigger = getPluginTrigger(pluginId)
const trigger = getPluginTrigger(pluginId);
if (trigger && trigger.trim() !== "") {
triggers[trigger] = pluginId
triggers[trigger] = pluginId;
}
}
return triggers
return triggers;
}
function getPluginsWithEmptyTrigger() {
const plugins = []
const launchers = getLauncherPlugins()
const plugins = [];
const launchers = getLauncherPlugins();
for (const pluginId in launchers) {
const trigger = getPluginTrigger(pluginId)
const trigger = getPluginTrigger(pluginId);
if (!trigger || trigger.trim() === "") {
plugins.push(pluginId)
plugins.push(pluginId);
}
}
return plugins
return plugins;
}
function getGlobalVar(pluginId, varName, defaultValue) {
if (globalVars[pluginId] && varName in globalVars[pluginId]) {
return globalVars[pluginId][varName]
return globalVars[pluginId][varName];
}
return defaultValue
return defaultValue;
}
function setGlobalVar(pluginId, varName, value) {
const newGlobals = Object.assign({}, globalVars)
const newGlobals = Object.assign({}, globalVars);
if (!newGlobals[pluginId]) {
newGlobals[pluginId] = {}
newGlobals[pluginId] = {};
}
newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId])
newGlobals[pluginId][varName] = value
globalVars = newGlobals
globalVarChanged(pluginId, varName)
newGlobals[pluginId] = Object.assign({}, newGlobals[pluginId]);
newGlobals[pluginId][varName] = value;
globalVars = newGlobals;
globalVarChanged(pluginId, varName);
}
}

View File

@@ -5,6 +5,7 @@ import QtQuick
import Quickshell
import Quickshell.Io
import Quickshell.Wayland
import qs.Common
Singleton {
id: root

View File

@@ -100,11 +100,15 @@ Item {
return;
closeTimer.stop();
shouldBeVisible = true;
if (useBackgroundWindow)
backgroundWindow.visible = true;
contentWindow.visible = true;
PopoutManager.showPopout(root);
opened();
Qt.callLater(() => {
if (shouldBeVisible) {
if (useBackgroundWindow)
backgroundWindow.visible = true;
contentWindow.visible = true;
PopoutManager.showPopout(root);
opened();
}
});
}
function close() {

View File

@@ -9,7 +9,7 @@ Type=simple
ExecStart=/usr/bin/dms run --session
ExecReload=/usr/bin/pkill -USR1 -x dms
Restart=always
RestartSec=2
RestartSec=1.23
TimeoutStopSec=10
[Install]

View File

@@ -2,6 +2,7 @@
//@ pragma Env QT_MEDIA_BACKEND=ffmpeg
//@ pragma Env QT_FFMPEG_DECODING_HW_DEVICE_TYPES=vaapi
//@ pragma Env QT_FFMPEG_ENCODING_HW_DEVICE_TYPES=vaapi
//@ pragma Env QT_WAYLAND_DISABLE_WINDOWDECORATION=1
//@ pragma UseQApplication
import QtQuick