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 echo "packages=${{ needs.check-updates.outputs.packages }}" >> $GITHUB_OUTPUT
fi 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 != '' if: steps.packages.outputs.version != ''
run: | run: |
VERSION="${{ steps.packages.outputs.version }}" VERSION="${{ steps.packages.outputs.version }}"
VERSION_NO_V="${VERSION#v}" VERSION_NO_V="${VERSION#v}"
echo "Updating packaging to version $VERSION_NO_V" echo "Updating packaging to version $VERSION_NO_V"
# Update openSUSE spec files # Update openSUSE dms spec (stable only)
sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/*.spec sed -i "s/^Version:.*/Version: $VERSION_NO_V/" distro/opensuse/dms.spec
# Update Debian _service files # Update Debian _service files
for service in distro/debian/*/_service; do 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" sed -i "s|<param name=\"revision\">v[0-9.]*</param>|<param name=\"revision\">$VERSION</param>|" "$service"
fi fi
done 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 - name: Install OSC
run: | run: |
@@ -203,13 +217,11 @@ jobs:
MESSAGE="Update to ${{ steps.packages.outputs.version }}" MESSAGE="Update to ${{ steps.packages.outputs.version }}"
fi fi
cd distro
if [[ "$PACKAGES" == "all" ]]; then if [[ "$PACKAGES" == "all" ]]; then
bash scripts/obs-upload.sh dms "$MESSAGE" bash distro/scripts/obs-upload.sh dms "$MESSAGE"
bash scripts/obs-upload.sh dms-git "Automated git update" bash distro/scripts/obs-upload.sh dms-git "Automated git update"
else else
bash scripts/obs-upload.sh "$PACKAGES" "$MESSAGE" bash distro/scripts/obs-upload.sh "$PACKAGES" "$MESSAGE"
fi fi
- name: Summary - name: Summary

View File

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

View File

@@ -1,7 +1,7 @@
%global debug_package %{nil} %global debug_package %{nil}
Name: dms-git Name: dms-git
Version: 0.6.2+git Version: 0.6.2+git2147.03073f68
Release: 5%{?dist} Release: 5%{?dist}
Epoch: 1 Epoch: 1
Summary: DankMaterialShell - Material 3 inspired shell (git nightly) Summary: DankMaterialShell - Material 3 inspired shell (git nightly)
@@ -102,6 +102,8 @@ fi
%{_userunitdir}/dms.service %{_userunitdir}/dms.service
%changelog %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 * Fri Nov 22 2025 AvengeMedia <maintainer@avengemedia.com> - 0.6.2+git-5
- Git nightly build from master branch - Git nightly build from master branch
- Multi-arch support (x86_64, aarch64) - 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 #!/bin/bash
# Generic PPA uploader for DMS packages # Ubuntu PPA uploader for DMS packages
# Usage: ./upload-ppa.sh <changes-file> <ppa-name> # Usage: ./upload-ppa.sh <changes-file> <ppa-name>
# #
# Example: # Example:

View File

@@ -53,8 +53,8 @@ PPA_NAME="${ARGS[1]}"
UBUNTU_SERIES="${ARGS[2]:-questing}" UBUNTU_SERIES="${ARGS[2]:-questing}"
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
BUILD_SCRIPT="$SCRIPT_DIR/create-source.sh" BUILD_SCRIPT="$SCRIPT_DIR/ppa-build.sh"
UPLOAD_SCRIPT="$SCRIPT_DIR/upload-ppa.sh" UPLOAD_SCRIPT="$SCRIPT_DIR/ppa-dput.sh"
# Validate scripts exist # Validate scripts exist
if [ ! -f "$BUILD_SCRIPT" ]; then 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" 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
import QtQuick.Controls import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Io
import qs.Common import qs.Common
import qs.Modals.FileBrowser import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets import qs.Widgets
FloatingWindow { FloatingWindow {
@@ -215,6 +213,7 @@ FloatingWindow {
objectName: "fileBrowserModal" objectName: "fileBrowserModal"
title: "Files - " + browserTitle title: "Files - " + browserTitle
minimumSize: Qt.size(500, 400)
implicitWidth: 800 implicitWidth: 800
implicitHeight: 600 implicitHeight: 600
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,4 @@
import QtQuick import QtQuick
import QtQuick.Controls
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
@@ -76,7 +75,6 @@ Column {
color: Theme.primary color: Theme.primary
anchors.centerIn: parent anchors.centerIn: parent
} }
} }
Item { Item {
@@ -90,7 +88,6 @@ Column {
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankFlickable { DankFlickable {
@@ -147,11 +144,8 @@ Column {
NumberAnimation { NumberAnimation {
duration: Theme.shortDuration duration: Theme.shortDuration
} }
} }
} }
} }
StyledText { StyledText {
@@ -163,182 +157,168 @@ Column {
horizontalAlignment: Text.AlignRight horizontalAlignment: Text.AlignRight
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
} }
} }
} }
} }
} }
Rectangle { Row {
width: parent.width width: parent.width
height: 80 height: 80
radius: Theme.cornerRadius spacing: Theme.spacingM
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 { Rectangle {
anchors.centerIn: parent width: (parent.width - Theme.spacingM) / 2
anchors.margins: Theme.spacingM height: 80
spacing: Theme.spacingM 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 { Row {
anchors.verticalCenter: parent.verticalCenter anchors.centerIn: parent
spacing: 4 spacing: Theme.spacingM
StyledText { Column {
text: I18n.tr("Memory") anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Theme.fontSizeLarge spacing: 4
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
}
}
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 { Column {
text: DgopService.totalMemoryKB > 0 ? `${((DgopService.usedMemoryKB / DgopService.totalMemoryKB) * 100).toFixed(1)}% used` : "No data" anchors.verticalCenter: parent.verticalCenter
font.pixelSize: Theme.fontSizeSmall spacing: 4
font.weight: Font.Bold width: 120
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)
Rectangle { Rectangle {
width: DgopService.totalSwapKB > 0 ? parent.width * (DgopService.usedSwapKB / DgopService.totalSwapKB) : 0 width: parent.width
height: parent.height height: 16
radius: parent.radius radius: 8
color: { color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
if (!DgopService.totalSwapKB) {
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3); 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) { Behavior on width {
return Theme.error; 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 { Row {
@@ -385,7 +365,6 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
Row { Row {
@@ -403,13 +382,9 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
} }
} }
} }
Rectangle { Rectangle {
@@ -451,7 +426,6 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText color: Theme.surfaceText
} }
} }
Row { Row {
@@ -469,15 +443,9 @@ Column {
font.weight: Font.Bold font.weight: Font.Bold
color: Theme.surfaceText 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 // ! 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 // ! That allows them to re-make with the right exclusiveZone
function notifyHorizontalBarChange() { function notifyHorizontalBarChange() {
if (!selectedBarIsVertical) { if (selectedBarIsVertical)
horizontalBarChangeDebounce.restart(); return;
} horizontalBarChangeDebounce.restart();
} }
function createNewBar() { function createNewBar() {
@@ -290,38 +290,44 @@ Item {
} }
function getWidgetsForSection(sectionId) { function getWidgetsForSection(sectionId) {
if (sectionId === "left") switch (sectionId) {
case "left":
return selectedBarConfig?.leftWidgets || []; return selectedBarConfig?.leftWidgets || [];
if (sectionId === "center") case "center":
return selectedBarConfig?.centerWidgets || []; return selectedBarConfig?.centerWidgets || [];
if (sectionId === "right") case "right":
return selectedBarConfig?.rightWidgets || []; return selectedBarConfig?.rightWidgets || [];
return []; default:
return [];
}
} }
function setWidgetsForSection(sectionId, widgets) { function setWidgetsForSection(sectionId, widgets) {
if (sectionId === "left") switch (sectionId) {
case "left":
SettingsData.updateBarConfig(selectedBarId, { SettingsData.updateBarConfig(selectedBarId, {
leftWidgets: widgets leftWidgets: widgets
}); });
else if (sectionId === "center") break;
case "center":
SettingsData.updateBarConfig(selectedBarId, { SettingsData.updateBarConfig(selectedBarId, {
centerWidgets: widgets centerWidgets: widgets
}); });
else if (sectionId === "right") break;
case "right":
SettingsData.updateBarConfig(selectedBarId, { SettingsData.updateBarConfig(selectedBarId, {
rightWidgets: widgets rightWidgets: widgets
}); });
break;
}
} }
function getWidgetsForPopup() { function getWidgetsForPopup() {
return baseWidgetDefinitions.filter(widget => { return baseWidgetDefinitions.filter(widget => {
if (widget.warning && widget.warning.includes("Plugin is disabled")) { if (widget.warning && widget.warning.includes("Plugin is disabled"))
return false; return false;
} if (widget.enabled === false)
if (widget.enabled === false) {
return false; return false;
}
return true; return true;
}); });
} }
@@ -646,36 +652,38 @@ Item {
for (var i = 0; i < widgets.length; i++) { for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i]; var widget = widgets[i];
var widgetId = typeof widget === "string" ? widget : widget.id; var widgetId = typeof widget === "string" ? widget : widget.id;
if (widgetId === itemId) { if (widgetId !== itemId)
if (typeof widget === "string") { continue;
widgets[i] = {
"id": widget, if (typeof widget === "string") {
"enabled": enabled widgets[i] = {
}; "id": widget,
} else { "enabled": enabled
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;
}
break; 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); setWidgetsForSection(sectionId, widgets);
} }
@@ -686,227 +694,251 @@ Item {
function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) { function handleSpacerSizeChanged(sectionId, widgetIndex, newSize) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
if (widgetIndex >= 0 && widgetIndex < widgets.length) { setWidgetsForSection(sectionId, widgets);
var widget = widgets[widgetIndex]; return;
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;
}
}
} }
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); setWidgetsForSection(sectionId, widgets);
} }
function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) { function handleGpuSelectionChanged(sectionId, widgetIndex, selectedGpuIndex) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
if (widgetIndex >= 0 && widgetIndex < widgets.length) { setWidgetsForSection(sectionId, widgets);
var widget = widgets[widgetIndex]; return;
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;
}
} }
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); setWidgetsForSection(sectionId, widgets);
} }
function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) { function handleDiskMountSelectionChanged(sectionId, widgetIndex, mountPath) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
if (widgetIndex >= 0 && widgetIndex < widgets.length) { setWidgetsForSection(sectionId, widgets);
var widget = widgets[widgetIndex]; return;
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;
}
} }
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); setWidgetsForSection(sectionId, widgets);
} }
function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) { function handleControlCenterSettingChanged(sectionId, widgetIndex, settingName, value) {
switch (settingName) { switch (settingName) {
case "showNetworkIcon": case "showNetworkIcon":
SettingsData.set("controlCenterShowNetworkIcon", value) SettingsData.set("controlCenterShowNetworkIcon", value);
break break;
case "showBluetoothIcon": case "showBluetoothIcon":
SettingsData.set("controlCenterShowBluetoothIcon", value) SettingsData.set("controlCenterShowBluetoothIcon", value);
break break;
case "showAudioIcon": case "showAudioIcon":
SettingsData.set("controlCenterShowAudioIcon", value) SettingsData.set("controlCenterShowAudioIcon", value);
break break;
case "showVpnIcon": case "showVpnIcon":
SettingsData.set("controlCenterShowVpnIcon", value) SettingsData.set("controlCenterShowVpnIcon", value);
break break;
case "showBrightnessIcon": case "showBrightnessIcon":
SettingsData.set("controlCenterShowBrightnessIcon", value) SettingsData.set("controlCenterShowBrightnessIcon", value);
break break;
case "showMicIcon": case "showMicIcon":
SettingsData.set("controlCenterShowMicIcon", value) SettingsData.set("controlCenterShowMicIcon", value);
break break;
case "showBatteryIcon": case "showBatteryIcon":
SettingsData.set("controlCenterShowBatteryIcon", value) SettingsData.set("controlCenterShowBatteryIcon", value);
break break;
case "showPrinterIcon": case "showPrinterIcon":
SettingsData.set("controlCenterShowPrinterIcon", value) SettingsData.set("controlCenterShowPrinterIcon", value);
break break;
} }
} }
function handlePrivacySettingChanged(sectionId, widgetIndex, settingName, value) { function handlePrivacySettingChanged(sectionId, widgetIndex, settingName, value) {
if (settingName === "showMicIcon") { switch (settingName) {
case "showMicIcon":
SettingsData.set("privacyShowMicIcon", value); SettingsData.set("privacyShowMicIcon", value);
} else if (settingName === "showCameraIcon") { break;
case "showCameraIcon":
SettingsData.set("privacyShowCameraIcon", value); SettingsData.set("privacyShowCameraIcon", value);
} else if (settingName === "showScreenSharingIcon") { break;
case "showScreenSharingIcon":
SettingsData.set("privacyShowScreenShareIcon", value); SettingsData.set("privacyShowScreenShareIcon", value);
break;
} }
} }
function handleMinimumWidthChanged(sectionId, widgetIndex, enabled) { function handleMinimumWidthChanged(sectionId, widgetIndex, enabled) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
if (widgetIndex >= 0 && widgetIndex < widgets.length) { setWidgetsForSection(sectionId, widgets);
var widget = widgets[widgetIndex]; return;
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;
}
} }
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); setWidgetsForSection(sectionId, widgets);
} }
function handleShowSwapChanged(sectionId, widgetIndex, enabled) { function handleShowSwapChanged(sectionId, widgetIndex, enabled) {
var widgets = getWidgetsForSection(sectionId).slice(); var widgets = getWidgetsForSection(sectionId).slice();
if (widgetIndex < 0 || widgetIndex >= widgets.length) {
if (widgetIndex >= 0 && widgetIndex < widgets.length) { setWidgetsForSection(sectionId, widgets);
var widget = widgets[widgetIndex]; return;
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;
}
} }
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); setWidgetsForSection(sectionId, widgets);
} }
@@ -932,7 +964,6 @@ Item {
"id": widget.id, "id": widget.id,
"enabled": widget.enabled "enabled": widget.enabled
}; };
if (widget.size !== undefined) if (widget.size !== undefined)
newWidget.size = widget.size; newWidget.size = widget.size;
if (widget.selectedGpuIndex !== undefined) if (widget.selectedGpuIndex !== undefined)
@@ -956,11 +987,10 @@ Item {
if (widget.keyboardLayoutNameCompactMode !== undefined) if (widget.keyboardLayoutNameCompactMode !== undefined)
newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode; newWidget.keyboardLayoutNameCompactMode = widget.keyboardLayoutNameCompactMode;
if (widget.id === "controlCenterButton") { if (widget.id === "controlCenterButton") {
newWidget.showNetworkIcon = widget.showNetworkIcon !== undefined ? widget.showNetworkIcon : true; newWidget.showNetworkIcon = widget.showNetworkIcon ?? true;
newWidget.showBluetoothIcon = widget.showBluetoothIcon !== undefined ? widget.showBluetoothIcon : true; newWidget.showBluetoothIcon = widget.showBluetoothIcon ?? true;
newWidget.showAudioIcon = widget.showAudioIcon !== undefined ? widget.showAudioIcon : true; newWidget.showAudioIcon = widget.showAudioIcon ?? true;
} }
widgets[i] = newWidget; widgets[i] = newWidget;
widget = newWidget; widget = newWidget;
} }
@@ -993,59 +1023,45 @@ Item {
var widgets = []; var widgets = [];
var widgetData = getWidgetsForSection(sectionId); var widgetData = getWidgetsForSection(sectionId);
widgetData.forEach(widget => { widgetData.forEach(widget => {
var widgetId = typeof widget === "string" ? widget : widget.id; var isString = typeof widget === "string";
var widgetEnabled = typeof widget === "string" ? true : widget.enabled; var widgetId = isString ? widget : widget.id;
var widgetSize = typeof widget === "string" ? undefined : widget.size; var widgetDef = baseWidgetDefinitions.find(w => w.id === widgetId);
var widgetSelectedGpuIndex = typeof widget === "string" ? undefined : widget.selectedGpuIndex; if (!widgetDef)
var widgetPciId = typeof widget === "string" ? undefined : widget.pciId; return;
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;
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; return widgets;
} }
@@ -1139,49 +1155,13 @@ Item {
implicitHeight: 1 implicitHeight: 1
} }
Rectangle { DankButton {
id: addBarBtn text: I18n.tr("Add Bar")
width: 100 iconName: "add"
height: 32 buttonHeight: 32
radius: Theme.cornerRadius
color: addBarArea.containsMouse ? Theme.primaryPressed : Theme.primary
visible: SettingsData.barConfigs.length < 4 visible: SettingsData.barConfigs.length < 4
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
onClicked: dankBarTab.createNewBar()
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
}
}
} }
} }
@@ -3284,7 +3264,6 @@ Item {
} }
} }
// Center/Middle Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: centerSection.implicitHeight + Theme.spacingL * 2 height: centerSection.implicitHeight + Theme.spacingL * 2
@@ -3343,7 +3322,6 @@ Item {
} }
} }
// Right/Bottom Section
StyledRect { StyledRect {
width: parent.width width: parent.width
height: rightSection.implicitHeight + Theme.spacingL * 2 height: rightSection.implicitHeight + Theme.spacingL * 2

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@ StyledRect {
property string expandedPluginId: "" property string expandedPluginId: ""
property bool hasUpdate: false property bool hasUpdate: false
property bool isReloading: false property bool isReloading: false
property var sharedTooltip: null
property string pluginId: pluginData ? pluginData.id : "" property string pluginId: pluginData ? pluginData.id : ""
property string pluginDirectoryName: { property string pluginDirectoryName: {
@@ -28,6 +29,10 @@ StyledRect {
property var pluginPermissions: pluginData ? (pluginData.permissions || []) : [] property var pluginPermissions: pluginData ? (pluginData.permissions || []) : []
property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== "" property bool hasSettings: pluginData && pluginData.settings !== undefined && pluginData.settings !== ""
property bool isExpanded: expandedPluginId === pluginId property bool isExpanded: expandedPluginId === pluginId
property bool isLoaded: {
PluginService.loadedPlugins;
return PluginService.loadedPlugins[pluginId] !== undefined;
}
width: parent.width width: parent.width
height: pluginItemColumn.implicitHeight + Theme.spacingM * 2 + settingsContainer.height height: pluginItemColumn.implicitHeight + Theme.spacingM * 2 + settingsContainer.height
@@ -63,7 +68,7 @@ StyledRect {
DankIcon { DankIcon {
name: root.pluginIcon name: root.pluginIcon
size: Theme.iconSize size: Theme.iconSize
color: PluginService.isPluginLoaded(root.pluginId) ? Theme.primary : Theme.surfaceVariantText color: root.isLoaded ? Theme.primary : Theme.surfaceVariantText
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
@@ -111,7 +116,7 @@ StyledRect {
height: 28 height: 28
radius: 14 radius: 14
color: updateArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" 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 { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
@@ -131,27 +136,21 @@ StyledRect {
DMSService.update(currentPluginName, response => { DMSService.update(currentPluginName, response => {
if (response.error) { if (response.error) {
ToastService.showError("Update failed: " + response.error); ToastService.showError("Update failed: " + response.error);
} else { return;
ToastService.showInfo("Plugin updated: " + currentPluginName);
PluginService.forceRescanPlugin(currentPluginId);
if (DMSService.apiVersion >= 8) {
DMSService.listInstalled();
}
} }
ToastService.showInfo("Plugin updated: " + currentPluginName);
PluginService.forceRescanPlugin(currentPluginId);
if (DMSService.apiVersion >= 8)
DMSService.listInstalled();
}); });
} }
onEntered: { onEntered: {
tooltipLoader.active = true; if (root.sharedTooltip)
if (tooltipLoader.item) { root.sharedTooltip.show(I18n.tr("Update Plugin"), parent, 0, 0, "top");
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Update Plugin"), p.x, p.y - 40, null);
}
} }
onExited: { onExited: {
if (tooltipLoader.item) { if (root.sharedTooltip)
tooltipLoader.item.hide(); root.sharedTooltip.hide();
}
tooltipLoader.active = false;
} }
} }
} }
@@ -180,27 +179,21 @@ StyledRect {
DMSService.uninstall(currentPluginName, response => { DMSService.uninstall(currentPluginName, response => {
if (response.error) { if (response.error) {
ToastService.showError("Uninstall failed: " + response.error); ToastService.showError("Uninstall failed: " + response.error);
} else { return;
ToastService.showInfo("Plugin uninstalled: " + currentPluginName);
PluginService.scanPlugins();
if (root.isExpanded) {
root.expandedPluginId = "";
}
} }
ToastService.showInfo("Plugin uninstalled: " + currentPluginName);
PluginService.scanPlugins();
if (root.isExpanded)
root.expandedPluginId = "";
}); });
} }
onEntered: { onEntered: {
tooltipLoader.active = true; if (root.sharedTooltip)
if (tooltipLoader.item) { root.sharedTooltip.show(I18n.tr("Uninstall Plugin"), parent, 0, 0, "top");
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Uninstall Plugin"), p.x, p.y - 40, null);
}
} }
onExited: { onExited: {
if (tooltipLoader.item) { if (root.sharedTooltip)
tooltipLoader.item.hide(); root.sharedTooltip.hide();
}
tooltipLoader.active = false;
} }
} }
} }
@@ -210,7 +203,7 @@ StyledRect {
height: 28 height: 28
radius: 14 radius: 14
color: reloadArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent" color: reloadArea.containsMouse ? Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency) : "transparent"
visible: PluginService.isPluginLoaded(root.pluginId) visible: root.isLoaded
DankIcon { DankIcon {
anchors.centerIn: parent anchors.centerIn: parent
@@ -230,23 +223,18 @@ StyledRect {
root.isReloading = true; root.isReloading = true;
if (PluginService.reloadPlugin(currentPluginId)) { if (PluginService.reloadPlugin(currentPluginId)) {
ToastService.showInfo("Plugin reloaded: " + currentPluginName); ToastService.showInfo("Plugin reloaded: " + currentPluginName);
} else { return;
ToastService.showError("Failed to reload plugin: " + currentPluginName);
root.isReloading = false;
} }
ToastService.showError("Failed to reload plugin: " + currentPluginName);
root.isReloading = false;
} }
onEntered: { onEntered: {
tooltipLoader.active = true; if (root.sharedTooltip)
if (tooltipLoader.item) { root.sharedTooltip.show(I18n.tr("Reload Plugin"), parent, 0, 0, "top");
const p = mapToItem(null, width / 2, 0);
tooltipLoader.item.show(I18n.tr("Reload Plugin"), p.x, p.y - 40, null);
}
} }
onExited: { onExited: {
if (tooltipLoader.item) { if (root.sharedTooltip)
tooltipLoader.item.hide(); root.sharedTooltip.hide();
}
tooltipLoader.active = false;
} }
} }
} }
@@ -254,7 +242,7 @@ StyledRect {
DankToggle { DankToggle {
id: pluginToggle id: pluginToggle
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
checked: PluginService.isPluginLoaded(root.pluginId) checked: root.isLoaded
onToggled: isChecked => { onToggled: isChecked => {
const currentPluginId = root.pluginId; const currentPluginId = root.pluginId;
const currentPluginName = root.pluginName; const currentPluginName = root.pluginName;
@@ -262,21 +250,18 @@ StyledRect {
if (isChecked) { if (isChecked) {
if (PluginService.enablePlugin(currentPluginId)) { if (PluginService.enablePlugin(currentPluginId)) {
ToastService.showInfo("Plugin enabled: " + currentPluginName); ToastService.showInfo("Plugin enabled: " + currentPluginName);
} else { return;
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;
} }
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 id: settingsLoader
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingL anchors.margins: Theme.spacingL
active: root.isExpanded && root.hasSettings && PluginService.isPluginLoaded(root.pluginId) active: root.isExpanded && root.hasSettings && root.isLoaded
asynchronous: false asynchronous: false
source: { source: {
@@ -376,16 +361,10 @@ StyledRect {
StyledText { StyledText {
anchors.centerIn: parent 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 font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText color: Theme.surfaceVariantText
visible: root.isExpanded && (!settingsLoader.active || settingsLoader.status === Loader.Error) 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 parentModal: null
property var installedPluginsData: ({}) property var installedPluginsData: ({})
property bool isReloading: false property bool isReloading: false
property alias sharedTooltip: sharedTooltip
focus: true focus: true
DankTooltipV2 {
id: sharedTooltip
}
DankFlickable { DankFlickable {
anchors.fill: parent anchors.fill: parent
clip: true clip: true
@@ -124,7 +129,7 @@ FocusScope {
iconName: "store" iconName: "store"
enabled: DMSService.dmsAvailable enabled: DMSService.dmsAvailable
onClicked: { onClicked: {
pluginBrowserModal.show(); pluginBrowser.show();
} }
} }
@@ -218,7 +223,7 @@ FocusScope {
Repeater { Repeater {
id: pluginRepeater id: pluginRepeater
model: PluginService.getAvailablePlugins() model: PluginService.availablePluginsList
PluginListItem { PluginListItem {
pluginData: modelData pluginData: modelData
@@ -229,6 +234,7 @@ FocusScope {
return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false; return pluginsTab.installedPluginsData[pluginId] || pluginsTab.installedPluginsData[pluginName] || false;
} }
isReloading: pluginsTab.isReloading isReloading: pluginsTab.isReloading
sharedTooltip: pluginsTab.sharedTooltip
onExpandedPluginIdChanged: { onExpandedPluginIdChanged: {
pluginsTab.expandedPluginId = expandedPluginId; pluginsTab.expandedPluginId = expandedPluginId;
} }
@@ -253,12 +259,7 @@ FocusScope {
} }
function refreshPluginList() { function refreshPluginList() {
Qt.callLater(() => { pluginsTab.isRefreshingPlugins = false;
var plugins = PluginService.getAvailablePlugins();
pluginRepeater.model = null;
pluginRepeater.model = plugins;
pluginsTab.isRefreshingPlugins = false;
});
} }
Connections { Connections {
@@ -286,9 +287,9 @@ FocusScope {
Connections { Connections {
target: DMSService target: DMSService
function onPluginsListReceived(plugins) { function onPluginsListReceived(plugins) {
pluginBrowserModal.isLoading = false; pluginBrowser.isLoading = false;
pluginBrowserModal.allPlugins = plugins; pluginBrowser.allPlugins = plugins;
pluginBrowserModal.updateFilteredPlugins(); pluginBrowser.updateFilteredPlugins();
} }
function onInstalledPluginsReceived(plugins) { function onInstalledPluginsReceived(plugins) {
var pluginMap = {}; var pluginMap = {};
@@ -314,13 +315,12 @@ FocusScope {
} }
Component.onCompleted: { Component.onCompleted: {
pluginBrowserModal.parentModal = pluginsTab.parentModal; pluginBrowser.parentModal = pluginsTab.parentModal;
if (DMSService.dmsAvailable && DMSService.apiVersion >= 8) { if (DMSService.dmsAvailable && DMSService.apiVersion >= 8)
DMSService.listInstalled(); DMSService.listInstalled();
}
} }
PluginBrowser { PluginBrowser {
id: pluginBrowserModal id: pluginBrowser
} }
} }

View File

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

View File

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

View File

@@ -11,48 +11,65 @@ Scope {
property bool searchActive: false property bool searchActive: false
property string searchActiveScreen: "" 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) { function showSpotlight(screenName) {
searchActive = true isClosing = false;
searchActiveScreen = screenName searchActive = true;
searchActiveScreen = screenName;
} }
function hideSpotlight() { function hideSpotlight() {
searchActive = false if (!searchActive)
searchActiveScreen = "" return;
isClosing = true;
}
function completeHide() {
searchActive = false;
searchActiveScreen = "";
isClosing = false;
} }
Connections { Connections {
target: NiriService target: NiriService
function onInOverviewChanged() { function onInOverviewChanged() {
if (!NiriService.inOverview) { if (!NiriService.inOverview) {
hideSpotlight() if (searchActive) {
} else { isClosing = true;
searchActive = false return;
searchActiveScreen = "" }
closeOverviewAfterAnim = false;
searchActive = false;
searchActiveScreen = "";
isClosing = false;
return;
} }
searchActive = false;
searchActiveScreen = "";
isClosing = false;
} }
function onCurrentOutputChanged() { function onCurrentOutputChanged() {
if (NiriService.inOverview && searchActive && searchActiveScreen !== "" && searchActiveScreen !== NiriService.currentOutput) { if (!NiriService.inOverview || !searchActive || searchActiveScreen === "" || searchActiveScreen === NiriService.currentOutput)
hideSpotlight() return;
} hideSpotlight();
} }
} }
Connections { Connections {
target: PopoutService.spotlightModal target: PopoutService.spotlightModal
function onSpotlightOpenChanged() { function onSpotlightOpenChanged() {
if (PopoutService.spotlightModal?.spotlightOpen && searchActive) { if (!PopoutService.spotlightModal?.spotlightOpen || !searchActive)
hideSpotlight() return;
} hideSpotlight();
} }
} }
Loader { Loader {
id: niriOverlayLoader id: niriOverlayLoader
active: overlayActive active: overlayActive || isClosing
asynchronous: false asynchronous: false
sourceComponent: Variants { sourceComponent: Variants {
@@ -65,29 +82,34 @@ Scope {
readonly property real dpr: CompositorService.getScreenScale(screen) readonly property real dpr: CompositorService.getScreenScale(screen)
readonly property bool isActiveScreen: screen.name === NiriService.currentOutput 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 screen: modelData
visible: NiriService.inOverview visible: NiriService.inOverview || niriOverviewScope.isClosing
color: "transparent" color: "transparent"
WlrLayershell.namespace: "dms:niri-overview-spotlight" WlrLayershell.namespace: "dms:niri-overview-spotlight"
WlrLayershell.layer: WlrLayer.Overlay WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: -1 WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: { WlrLayershell.keyboardFocus: {
if (!NiriService.inOverview) return WlrKeyboardFocus.None if (!NiriService.inOverview)
if (!isActiveScreen) return WlrKeyboardFocus.None return WlrKeyboardFocus.None;
return WlrKeyboardFocus.Exclusive if (!isActiveScreen)
return WlrKeyboardFocus.None;
if (niriOverviewScope.isClosing)
return WlrKeyboardFocus.None;
return WlrKeyboardFocus.Exclusive;
} }
mask: Region { mask: Region {
item: shouldShowSpotlight ? spotlightContainer : null item: spotlightContainer.visible ? spotlightContainer : null
} }
onShouldShowSpotlightChanged: { onShouldShowSpotlightChanged: {
if (!shouldShowSpotlight && isActiveScreen) { if (shouldShowSpotlight || !isActiveScreen)
Qt.callLater(() => keyboardFocusScope.forceActiveFocus()) return;
} Qt.callLater(() => keyboardFocusScope.forceActiveFocus());
} }
anchors { anchors {
@@ -97,61 +119,62 @@ Scope {
bottom: true bottom: true
} }
FocusScope { FocusScope {
id: keyboardFocusScope id: keyboardFocusScope
anchors.fill: parent anchors.fill: parent
focus: true focus: true
Keys.onPressed: event => { Keys.onPressed: event => {
if (!overlayWindow.shouldShowSpotlight) { if (overlayWindow.shouldShowSpotlight || niriOverviewScope.isClosing)
if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) { return;
NiriService.toggleOverview() if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) {
event.accepted = true NiriService.toggleOverview();
return 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 (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) width: Theme.px(500, overlayWindow.dpr)
height: Theme.px(600, 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 Connections {
opacity: overlayWindow.shouldShowSpotlight ? 1 : 0 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 enabled: overlayWindow.shouldShowSpotlight
layer.enabled: true layer.enabled: true
layer.smooth: false layer.smooth: false
layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr)) layer.textureSize: Qt.size(Math.round(width * overlayWindow.dpr), Math.round(height * overlayWindow.dpr))
Connections { Behavior on scale {
target: overlayWindow
function onShouldShowSpotlightChanged() {
spotlightContainer.scaleValue = overlayWindow.shouldShowSpotlight ? 1.0 : 0.96
}
}
Behavior on scaleValue {
NumberAnimation { NumberAnimation {
duration: Theme.expressiveDurations.expressiveDefaultSpatial duration: Theme.expressiveDurations.expressiveDefaultSpatial
easing.type: Easing.BezierSpline 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 { NumberAnimation {
duration: Theme.expressiveDurations.expressiveDefaultSpatial duration: Theme.expressiveDurations.expressiveDefaultSpatial
easing.type: Easing.BezierSpline 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 anchors.margins: 0
property var fakeParentModal: QtObject { property var fakeParentModal: QtObject {
property bool spotlightOpen: overlayWindow.shouldShowSpotlight property bool spotlightOpen: spotlightContainer.visible
function hide() { function hide() {
niriOverviewScope.hideSpotlight() niriOverviewScope.hideSpotlight();
if (overlayWindow.isActiveScreen) {
Qt.callLater(() => keyboardFocusScope.forceActiveFocus())
}
} }
} }
Component.onCompleted: { Component.onCompleted: {
parentModal = fakeParentModal parentModal = fakeParentModal;
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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