mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
849bf16388
- Use Quickshell.Networking for wifiEnabled - Improve state synchronization between processes - Fix race conditions in Wi-Fi scanning - Ensure proper startup initialization - Another icon fix xD (4th one) - Merge deviceStatus with wifiDetails Co-Authored-By: notiant <notiant@users.noreply.github.com>
338 lines
10 KiB
QML
338 lines
10 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell
|
|
import Quickshell.Io
|
|
import qs.Commons
|
|
import qs.Services.Theming
|
|
|
|
// Service to check if various programs are available on the system
|
|
Singleton {
|
|
id: root
|
|
|
|
// Program availability properties
|
|
property bool nmcliAvailable: false
|
|
property bool bluetoothctlAvailable: false
|
|
property bool wlsunsetAvailable: false
|
|
property bool gnomeCalendarAvailable: false
|
|
property bool pythonAvailable: false
|
|
property bool wtypeAvailable: false
|
|
|
|
// Programs to check - maps property names to commands
|
|
readonly property var programsToCheck: ({
|
|
"bluetoothctlAvailable": ["sh", "-c", "command -v bluetoothctl"],
|
|
"nmcliAvailable": ["sh", "-c", "command -v nmcli"],
|
|
"wlsunsetAvailable": ["sh", "-c", "command -v wlsunset"],
|
|
"gnomeCalendarAvailable": ["sh", "-c", "command -v gnome-calendar"],
|
|
"wtypeAvailable": ["sh", "-c", "command -v wtype"],
|
|
"pythonAvailable": ["sh", "-c", "command -v python3"]
|
|
})
|
|
|
|
// Discord client auto-detection
|
|
property var availableDiscordClients: []
|
|
|
|
// Code client auto-detection
|
|
property var availableCodeClients: []
|
|
|
|
// Emacs client auto-detection
|
|
property var availableEmacsClients: []
|
|
|
|
// Signal emitted when all checks are complete
|
|
signal checksCompleted
|
|
|
|
// disable Night Light in settings if wlsunset is not available
|
|
onChecksCompleted: {
|
|
if (!wlsunsetAvailable && Settings.data.nightLight.enabled) {
|
|
Settings.data.nightLight.enabled = false;
|
|
}
|
|
}
|
|
|
|
onWlsunsetAvailableChanged: {
|
|
if (!wlsunsetAvailable && Settings.data.nightLight.enabled) {
|
|
Settings.data.nightLight.enabled = false;
|
|
}
|
|
}
|
|
|
|
// Function to detect Discord client by checking config directories
|
|
function detectDiscordClient() {
|
|
// Build shell script to check each client
|
|
var scriptParts = ["available_clients=\"\";"];
|
|
|
|
for (var i = 0; i < TemplateRegistry.discordClients.length; i++) {
|
|
var client = TemplateRegistry.discordClients[i];
|
|
var clientName = client.name;
|
|
var configPath = client.configPath;
|
|
|
|
// Use the actual config path from the client, removing ~ prefix
|
|
var checkPath = configPath.startsWith("~") ? configPath.substring(2) : configPath.substring(1);
|
|
|
|
scriptParts.push("if [ -d \"$HOME/" + checkPath + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;");
|
|
}
|
|
|
|
scriptParts.push("echo \"$available_clients\"");
|
|
|
|
// Use a Process to check directory existence for all clients
|
|
discordDetector.command = ["sh", "-c", scriptParts.join(" ")];
|
|
discordDetector.running = true;
|
|
}
|
|
|
|
// Process to detect Discord client directories
|
|
Process {
|
|
id: discordDetector
|
|
running: false
|
|
|
|
onExited: function (exitCode) {
|
|
availableDiscordClients = [];
|
|
|
|
if (exitCode === 0) {
|
|
var detectedClients = stdout.text.trim().split(/\s+/).filter(function (client) {
|
|
return client.length > 0;
|
|
});
|
|
|
|
if (detectedClients.length > 0) {
|
|
// Build list of available clients
|
|
for (var i = 0; i < detectedClients.length; i++) {
|
|
var clientName = detectedClients[i];
|
|
for (var j = 0; j < TemplateRegistry.discordClients.length; j++) {
|
|
var client = TemplateRegistry.discordClients[j];
|
|
if (client.name === clientName) {
|
|
availableDiscordClients.push(client);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Logger.d("ProgramChecker", "Detected Discord clients:", detectedClients.join(", "));
|
|
}
|
|
}
|
|
|
|
if (availableDiscordClients.length === 0) {
|
|
Logger.d("ProgramChecker", "No Discord clients detected");
|
|
}
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
stderr: StdioCollector {}
|
|
}
|
|
|
|
// Function to detect Code client by checking config directories
|
|
function detectCodeClient() {
|
|
// Build shell script to check each client
|
|
var scriptParts = ["available_clients=\"\";"];
|
|
|
|
for (var i = 0; i < TemplateRegistry.codeClients.length; i++) {
|
|
var client = TemplateRegistry.codeClients[i];
|
|
var clientName = client.name;
|
|
var configPath = client.configPath;
|
|
|
|
// Check if the config directory exists
|
|
scriptParts.push("if [ -d \"$HOME" + configPath.substring(1) + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;");
|
|
}
|
|
|
|
scriptParts.push("echo \"$available_clients\"");
|
|
|
|
// Use a Process to check directory existence for all clients
|
|
codeDetector.command = ["sh", "-c", scriptParts.join(" ")];
|
|
codeDetector.running = true;
|
|
}
|
|
|
|
// Process to detect Code client directories
|
|
Process {
|
|
id: codeDetector
|
|
running: false
|
|
|
|
onExited: function (exitCode) {
|
|
availableCodeClients = [];
|
|
|
|
if (exitCode === 0) {
|
|
var detectedClients = stdout.text.trim().split(/\s+/).filter(function (client) {
|
|
return client.length > 0;
|
|
});
|
|
|
|
if (detectedClients.length > 0) {
|
|
// Build list of available clients
|
|
for (var i = 0; i < detectedClients.length; i++) {
|
|
var clientName = detectedClients[i];
|
|
for (var j = 0; j < TemplateRegistry.codeClients.length; j++) {
|
|
var client = TemplateRegistry.codeClients[j];
|
|
if (client.name === clientName) {
|
|
availableCodeClients.push(client);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Logger.d("ProgramChecker", "Detected Code clients:", detectedClients.join(", "));
|
|
}
|
|
}
|
|
|
|
if (availableCodeClients.length === 0) {
|
|
Logger.d("ProgramChecker", "No Code clients detected");
|
|
}
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
stderr: StdioCollector {}
|
|
}
|
|
|
|
// Function to detect Emacs client by checking config directories
|
|
function detectEmacsClient() {
|
|
// Build shell script to check each client
|
|
var scriptParts = ["available_clients=\"\";"];
|
|
|
|
for (var i = 0; i < TemplateRegistry.emacsClients.length; i++) {
|
|
var client = TemplateRegistry.emacsClients[i];
|
|
var clientName = client.name;
|
|
var configPath = client.path;
|
|
|
|
// Check if the config directory exists
|
|
scriptParts.push("if [ -d \"$HOME" + configPath.substring(1) + "\" ]; then available_clients=\"$available_clients " + clientName + "\"; fi;");
|
|
}
|
|
|
|
scriptParts.push("echo \"$available_clients\"");
|
|
|
|
// Use a Process to check directory existence for all clients
|
|
emacsDetector.command = ["sh", "-c", scriptParts.join(" ")];
|
|
emacsDetector.running = true;
|
|
}
|
|
|
|
// Process to detect Emacs client directories
|
|
Process {
|
|
id: emacsDetector
|
|
running: false
|
|
|
|
onExited: function (exitCode) {
|
|
availableEmacsClients = [];
|
|
|
|
if (exitCode === 0) {
|
|
var detectedClients = stdout.text.trim().split(/\s+/).filter(function (client) {
|
|
return client.length > 0;
|
|
});
|
|
|
|
if (detectedClients.length > 0) {
|
|
// Build list of available clients
|
|
for (var i = 0; i < detectedClients.length; i++) {
|
|
var clientName = detectedClients[i];
|
|
for (var j = 0; j < TemplateRegistry.emacsClients.length; j++) {
|
|
var client = TemplateRegistry.emacsClients[j];
|
|
if (client.name === clientName) {
|
|
availableEmacsClients.push(client);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Logger.d("ProgramChecker", "Detected Emacs clients:", detectedClients.join(", "));
|
|
}
|
|
}
|
|
|
|
if (availableEmacsClients.length === 0) {
|
|
Logger.d("ProgramChecker", "No Emacs clients detected");
|
|
}
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
stderr: StdioCollector {}
|
|
}
|
|
|
|
// Internal tracking
|
|
property int completedChecks: 0
|
|
property int totalChecks: Object.keys(programsToCheck).length
|
|
|
|
// Single reusable Process object
|
|
Process {
|
|
id: checker
|
|
running: false
|
|
|
|
property string currentProperty: ""
|
|
|
|
onExited: function (exitCode) {
|
|
// Set the availability property
|
|
root[currentProperty] = (exitCode === 0);
|
|
|
|
// Stop the process to free resources
|
|
running = false;
|
|
|
|
// Track completion
|
|
root.completedChecks++;
|
|
|
|
// Check next program or emit completion signal
|
|
if (root.completedChecks >= root.totalChecks) {
|
|
// Run Discord, Code and Emacs client detection after all checks are complete
|
|
root.detectDiscordClient();
|
|
root.detectCodeClient();
|
|
root.detectEmacsClient();
|
|
root.checksCompleted();
|
|
} else {
|
|
root.checkNextProgram();
|
|
}
|
|
}
|
|
|
|
stdout: StdioCollector {}
|
|
stderr: StdioCollector {}
|
|
}
|
|
|
|
// Queue of programs to check
|
|
property var checkQueue: []
|
|
property int currentCheckIndex: 0
|
|
|
|
// Function to check the next program in the queue
|
|
function checkNextProgram() {
|
|
if (currentCheckIndex >= checkQueue.length)
|
|
return;
|
|
var propertyName = checkQueue[currentCheckIndex];
|
|
var command = programsToCheck[propertyName];
|
|
|
|
checker.currentProperty = propertyName;
|
|
checker.command = command;
|
|
checker.running = true;
|
|
|
|
currentCheckIndex++;
|
|
}
|
|
|
|
// Function to run all program checks
|
|
function checkAllPrograms() {
|
|
// Reset state
|
|
completedChecks = 0;
|
|
currentCheckIndex = 0;
|
|
checkQueue = Object.keys(programsToCheck);
|
|
|
|
// Start first check
|
|
if (checkQueue.length > 0) {
|
|
checkNextProgram();
|
|
}
|
|
}
|
|
|
|
// Function to check a specific program
|
|
function checkProgram(programProperty) {
|
|
if (!programsToCheck.hasOwnProperty(programProperty)) {
|
|
Logger.w("ProgramChecker", "Unknown program property:", programProperty);
|
|
return;
|
|
}
|
|
|
|
checker.currentProperty = programProperty;
|
|
checker.command = programsToCheck[programProperty];
|
|
checker.running = true;
|
|
}
|
|
|
|
// Manual function to test Discord detection (for debugging)
|
|
function testDiscordDetection() {
|
|
Logger.d("ProgramChecker", "Testing Discord detection...");
|
|
Logger.d("ProgramChecker", "HOME:", Quickshell.env("HOME"));
|
|
|
|
// Test each client directory
|
|
for (var i = 0; i < TemplateRegistry.discordClients.length; i++) {
|
|
var client = TemplateRegistry.discordClients[i];
|
|
var configDir = client.configPath.replace("~", Quickshell.env("HOME"));
|
|
Logger.d("ProgramChecker", "Checking:", configDir);
|
|
}
|
|
|
|
detectDiscordClient();
|
|
}
|
|
|
|
// Initialize checks when service is created
|
|
Component.onCompleted: {
|
|
checkAllPrograms();
|
|
}
|
|
}
|