mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
cups: add comprehensive CUPs setting page
- Add printers - Delete printers - Use polkit APIs as fallback on auth errors - Fix ref system to conditionally subscribe to cups when wanted
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
@@ -12,20 +10,179 @@ Singleton {
|
||||
|
||||
property int refCount: 0
|
||||
|
||||
onRefCountChanged: {
|
||||
if (refCount > 0) {
|
||||
ensureSubscription();
|
||||
} else if (refCount === 0 && DMSService.activeSubscriptions.includes("cups")) {
|
||||
DMSService.removeSubscription("cups");
|
||||
}
|
||||
}
|
||||
|
||||
function ensureSubscription() {
|
||||
if (refCount <= 0)
|
||||
return;
|
||||
if (!DMSService.isConnected)
|
||||
return;
|
||||
if (DMSService.activeSubscriptions.includes("cups"))
|
||||
return;
|
||||
if (DMSService.activeSubscriptions.includes("all"))
|
||||
return;
|
||||
DMSService.addSubscription("cups");
|
||||
if (cupsAvailable) {
|
||||
getState();
|
||||
}
|
||||
}
|
||||
|
||||
property var printerNames: []
|
||||
property var printers: []
|
||||
property string selectedPrinter: ""
|
||||
property string expandedPrinter: ""
|
||||
|
||||
property bool cupsAvailable: false
|
||||
property bool stateInitialized: false
|
||||
|
||||
property var devices: []
|
||||
property var ppds: []
|
||||
property var printerClasses: []
|
||||
|
||||
readonly property var filteredDevices: {
|
||||
if (!devices || devices.length === 0)
|
||||
return [];
|
||||
const bareProtocols = ["ipp", "ipps", "http", "https", "lpd", "socket", "beh", "dnssd", "mdns", "smb", "file", "cups-brf"];
|
||||
|
||||
// First pass: filter out invalid/bare protocol entries
|
||||
const validDevices = devices.filter(d => {
|
||||
if (!d.uri)
|
||||
return false;
|
||||
const uriLower = d.uri.toLowerCase();
|
||||
for (let proto of bareProtocols) {
|
||||
if (uriLower === proto || uriLower === proto + ":")
|
||||
return false;
|
||||
}
|
||||
if (d.class === "network" && d.info === "Backend Error Handler")
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
// Second pass: prefer IPP over LPD for the same printer
|
||||
// _printer._tcp (LPD) doesn't work well with driverless printing
|
||||
// _ipp._tcp or _ipps._tcp (IPP) should be preferred
|
||||
const ippDeviceHosts = new Set();
|
||||
for (const d of validDevices) {
|
||||
if (!d.uri)
|
||||
continue;
|
||||
// Extract hostname from dnssd URIs like dnssd://Name%20[mac]._ipp._tcp.local
|
||||
const ippMatch = d.uri.match(/dnssd:\/\/[^/]*\._ipps?\._tcp/);
|
||||
if (ippMatch) {
|
||||
// Extract the unique identifier (usually MAC address in brackets)
|
||||
const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
|
||||
if (macMatch)
|
||||
ippDeviceHosts.add(macMatch[1].toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out _printer._tcp devices when we have _ipp._tcp for the same printer
|
||||
return validDevices.filter(d => {
|
||||
if (!d.uri)
|
||||
return true;
|
||||
// If this is an LPD device, check if we have an IPP alternative
|
||||
if (d.uri.includes("._printer._tcp")) {
|
||||
const macMatch = d.uri.match(/\[([a-f0-9]+)\]/i);
|
||||
if (macMatch && ippDeviceHosts.has(macMatch[1].toLowerCase())) {
|
||||
return false; // Skip LPD device, we have IPP
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
function decodeUri(str) {
|
||||
if (!str)
|
||||
return "";
|
||||
try {
|
||||
return decodeURIComponent(str.replace(/\+/g, " "));
|
||||
} catch (e) {
|
||||
return str;
|
||||
}
|
||||
}
|
||||
|
||||
function getDeviceDisplayName(device) {
|
||||
if (!device)
|
||||
return "";
|
||||
if (device.info && device.info.length > 0) {
|
||||
return decodeUri(device.info);
|
||||
}
|
||||
if (device.makeModel && device.makeModel.length > 0) {
|
||||
return decodeUri(device.makeModel);
|
||||
}
|
||||
return decodeUri(device.uri);
|
||||
}
|
||||
|
||||
function getDeviceSubtitle(device) {
|
||||
if (!device)
|
||||
return "";
|
||||
const parts = [];
|
||||
if (device.class) {
|
||||
switch (device.class) {
|
||||
case "direct":
|
||||
parts.push(I18n.tr("Local"));
|
||||
break;
|
||||
case "network":
|
||||
parts.push(I18n.tr("Network"));
|
||||
break;
|
||||
case "file":
|
||||
parts.push(I18n.tr("File"));
|
||||
break;
|
||||
default:
|
||||
parts.push(device.class);
|
||||
}
|
||||
}
|
||||
if (device.location)
|
||||
parts.push(decodeUri(device.location));
|
||||
return parts.join(" • ");
|
||||
}
|
||||
|
||||
function suggestPrinterName(device) {
|
||||
if (!device)
|
||||
return "";
|
||||
let name = device.info || device.makeModel || "";
|
||||
name = name.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
||||
return name.substring(0, 32) || "Printer";
|
||||
}
|
||||
|
||||
function getMatchingPPDs(device) {
|
||||
if (!device || !ppds || ppds.length === 0)
|
||||
return [];
|
||||
const isDnssd = device.uri && (device.uri.startsWith("dnssd://") || device.uri.startsWith("ipp://") || device.uri.startsWith("ipps://"));
|
||||
if (isDnssd) {
|
||||
const driverless = ppds.filter(p => p.name === "driverless" || p.name === "everywhere" || (p.makeModel && p.makeModel.toLowerCase().includes("driverless")));
|
||||
if (driverless.length > 0)
|
||||
return driverless;
|
||||
}
|
||||
if (!device.makeModel)
|
||||
return [];
|
||||
const makeModelLower = device.makeModel.toLowerCase();
|
||||
const words = makeModelLower.split(/[\s_-]+/).filter(w => w.length > 2);
|
||||
return ppds.filter(p => {
|
||||
if (!p.makeModel)
|
||||
return false;
|
||||
const ppdLower = p.makeModel.toLowerCase();
|
||||
return words.some(w => ppdLower.includes(w));
|
||||
}).slice(0, 10);
|
||||
}
|
||||
|
||||
property bool loadingDevices: false
|
||||
property bool loadingPPDs: false
|
||||
property bool loadingClasses: false
|
||||
property bool creatingPrinter: false
|
||||
|
||||
signal cupsStateUpdate
|
||||
|
||||
readonly property string socketPath: Quickshell.env("DMS_SOCKET")
|
||||
|
||||
Component.onCompleted: {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
checkDMSCapabilities()
|
||||
checkDMSCapabilities();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +191,8 @@ Singleton {
|
||||
|
||||
function onConnectionStateChanged() {
|
||||
if (DMSService.isConnected) {
|
||||
checkDMSCapabilities()
|
||||
checkDMSCapabilities();
|
||||
ensureSubscription();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,328 +202,641 @@ Singleton {
|
||||
enabled: DMSService.isConnected
|
||||
|
||||
function onCupsStateUpdate(data) {
|
||||
console.log("CupsService: Subscription update received")
|
||||
getState()
|
||||
console.log("CupsService: Subscription update received");
|
||||
getState();
|
||||
}
|
||||
|
||||
function onCapabilitiesChanged() {
|
||||
checkDMSCapabilities()
|
||||
checkDMSCapabilities();
|
||||
}
|
||||
}
|
||||
|
||||
function checkDMSCapabilities() {
|
||||
if (!DMSService.isConnected) {
|
||||
return
|
||||
}
|
||||
|
||||
if (DMSService.capabilities.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
cupsAvailable = DMSService.capabilities.includes("cups")
|
||||
if (!DMSService.isConnected)
|
||||
return;
|
||||
if (DMSService.capabilities.length === 0)
|
||||
return;
|
||||
cupsAvailable = DMSService.capabilities.includes("cups");
|
||||
|
||||
if (cupsAvailable && !stateInitialized) {
|
||||
stateInitialized = true
|
||||
getState()
|
||||
stateInitialized = true;
|
||||
getState();
|
||||
}
|
||||
}
|
||||
|
||||
function getState() {
|
||||
if (!cupsAvailable)
|
||||
return
|
||||
|
||||
return;
|
||||
DMSService.sendRequest("cups.getPrinters", null, response => {
|
||||
if (response.result) {
|
||||
updatePrinters(response.result)
|
||||
fetchAllJobs()
|
||||
}
|
||||
})
|
||||
if (response.result) {
|
||||
updatePrinters(response.result);
|
||||
fetchAllJobs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updatePrinters(printersData) {
|
||||
printerNames = printersData.map(p => p.name)
|
||||
printerNames = printersData.map(p => p.name);
|
||||
|
||||
let printersObj = {}
|
||||
let printersObj = {};
|
||||
for (var i = 0; i < printersData.length; i++) {
|
||||
let printer = printersData[i]
|
||||
let printer = printersData[i];
|
||||
printersObj[printer.name] = {
|
||||
"name": printer.name,
|
||||
"uri": printer.uri || "",
|
||||
"state": printer.state,
|
||||
"stateReason": printer.stateReason,
|
||||
"location": printer.location || "",
|
||||
"info": printer.info || "",
|
||||
"makeModel": printer.makeModel || "",
|
||||
"accepting": printer.accepting !== false,
|
||||
"jobs": []
|
||||
}
|
||||
};
|
||||
}
|
||||
printers = printersObj
|
||||
printers = printersObj;
|
||||
|
||||
if (printerNames.length > 0) {
|
||||
if (selectedPrinter.length > 0) {
|
||||
if (!printerNames.includes(selectedPrinter)) {
|
||||
selectedPrinter = printerNames[0]
|
||||
selectedPrinter = printerNames[0];
|
||||
}
|
||||
} else {
|
||||
selectedPrinter = printerNames[0]
|
||||
selectedPrinter = printerNames[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function fetchAllJobs() {
|
||||
for (var i = 0; i < printerNames.length; i++) {
|
||||
fetchJobsForPrinter(printerNames[i])
|
||||
fetchJobsForPrinter(printerNames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchJobsForPrinter(printerName) {
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
}
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.getJobs", params, response => {
|
||||
if (response.result && printers[printerName]) {
|
||||
let updatedPrinters = Object.assign({}, printers)
|
||||
updatedPrinters[printerName].jobs = response.result
|
||||
printers = updatedPrinters
|
||||
}
|
||||
})
|
||||
if (response.result && printers[printerName]) {
|
||||
let updatedPrinters = Object.assign({}, printers);
|
||||
updatedPrinters[printerName].jobs = response.result;
|
||||
printers = updatedPrinters;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getSelectedPrinter() {
|
||||
return selectedPrinter
|
||||
return selectedPrinter;
|
||||
}
|
||||
|
||||
function setSelectedPrinter(printerName) {
|
||||
if (printerNames.length > 0) {
|
||||
if (printerNames.includes(printerName)) {
|
||||
selectedPrinter = printerName
|
||||
selectedPrinter = printerName;
|
||||
} else {
|
||||
selectedPrinter = printerNames[0]
|
||||
selectedPrinter = printerNames[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getPrintersNum() {
|
||||
if (!cupsAvailable)
|
||||
return 0
|
||||
return 0;
|
||||
|
||||
return printerNames.length
|
||||
return printerNames.length;
|
||||
}
|
||||
|
||||
function getPrintersNames() {
|
||||
if (!cupsAvailable)
|
||||
return []
|
||||
return [];
|
||||
|
||||
return printerNames
|
||||
return printerNames;
|
||||
}
|
||||
|
||||
function getTotalJobsNum() {
|
||||
if (!cupsAvailable)
|
||||
return 0
|
||||
return 0;
|
||||
|
||||
var result = 0
|
||||
var result = 0;
|
||||
for (var i = 0; i < printerNames.length; i++) {
|
||||
var printerName = printerNames[i]
|
||||
var printerName = printerNames[i];
|
||||
if (printers[printerName] && printers[printerName].jobs) {
|
||||
result += printers[printerName].jobs.length
|
||||
result += printers[printerName].jobs.length;
|
||||
}
|
||||
}
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
|
||||
function getCurrentPrinterState() {
|
||||
if (!cupsAvailable || !selectedPrinter)
|
||||
return ""
|
||||
return "";
|
||||
|
||||
var printer = printers[selectedPrinter]
|
||||
return printer.state
|
||||
var printer = printers[selectedPrinter];
|
||||
return printer.state;
|
||||
}
|
||||
|
||||
function getCurrentPrinterStatePrettyShort() {
|
||||
if (!cupsAvailable || !selectedPrinter)
|
||||
return ""
|
||||
return "";
|
||||
|
||||
var printer = printers[selectedPrinter]
|
||||
return getPrinterStateTranslation(printer.state) + " (" + getPrinterStateReasonTranslation(printer.stateReason) + ")"
|
||||
var printer = printers[selectedPrinter];
|
||||
return getPrinterStateTranslation(printer.state) + " (" + getPrinterStateReasonTranslation(printer.stateReason) + ")";
|
||||
}
|
||||
|
||||
function getCurrentPrinterStatePretty() {
|
||||
if (!cupsAvailable || !selectedPrinter)
|
||||
return ""
|
||||
return "";
|
||||
|
||||
var printer = printers[selectedPrinter]
|
||||
return getPrinterStateTranslation(printer.state) + " (" + I18n.tr("Reason") + ": " + getPrinterStateReasonTranslation(printer.stateReason) + ")"
|
||||
var printer = printers[selectedPrinter];
|
||||
return getPrinterStateTranslation(printer.state) + " (" + I18n.tr("Reason") + ": " + getPrinterStateReasonTranslation(printer.stateReason) + ")";
|
||||
}
|
||||
|
||||
function getCurrentPrinterJobs() {
|
||||
if (!cupsAvailable || !selectedPrinter)
|
||||
return []
|
||||
return [];
|
||||
|
||||
return getJobs(selectedPrinter)
|
||||
return getJobs(selectedPrinter);
|
||||
}
|
||||
|
||||
function getJobs(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return ""
|
||||
return "";
|
||||
|
||||
var printer = printers[printerName]
|
||||
return printer.jobs
|
||||
var printer = printers[printerName];
|
||||
return printer.jobs;
|
||||
}
|
||||
|
||||
function getJobsNum(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return 0
|
||||
return 0;
|
||||
|
||||
var printer = printers[printerName]
|
||||
return printer.jobs.length
|
||||
var printer = printers[printerName];
|
||||
return printer.jobs.length;
|
||||
}
|
||||
|
||||
function pausePrinter(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return
|
||||
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
}
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.pausePrinter", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to pause printer") + " - " + response.error)
|
||||
} else {
|
||||
getState()
|
||||
}
|
||||
})
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to pause printer") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function resumePrinter(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return
|
||||
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
}
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.resumePrinter", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to resume printer") + " - " + response.error)
|
||||
} else {
|
||||
getState()
|
||||
}
|
||||
})
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to resume printer") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function cancelJob(printerName, jobID) {
|
||||
if (!cupsAvailable)
|
||||
return
|
||||
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName,
|
||||
"jobID": jobID
|
||||
}
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.cancelJob", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to cancel selected job") + " - " + response.error)
|
||||
} else {
|
||||
fetchJobsForPrinter(printerName)
|
||||
}
|
||||
})
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to cancel selected job") + " - " + response.error);
|
||||
} else {
|
||||
fetchJobsForPrinter(printerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function purgeJobs(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return
|
||||
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
}
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.purgeJobs", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to cancel all jobs") + " - " + response.error)
|
||||
} else {
|
||||
fetchJobsForPrinter(printerName)
|
||||
}
|
||||
})
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to cancel all jobs") + " - " + response.error);
|
||||
} else {
|
||||
fetchJobsForPrinter(printerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getDevices() {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
loadingDevices = true;
|
||||
DMSService.sendRequest("cups.getDevices", null, response => {
|
||||
loadingDevices = false;
|
||||
if (response.result) {
|
||||
devices = response.result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPPDs() {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
loadingPPDs = true;
|
||||
DMSService.sendRequest("cups.getPPDs", null, response => {
|
||||
loadingPPDs = false;
|
||||
if (response.result) {
|
||||
ppds = response.result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getClasses() {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
loadingClasses = true;
|
||||
DMSService.sendRequest("cups.getClasses", null, response => {
|
||||
loadingClasses = false;
|
||||
if (response.result) {
|
||||
printerClasses = response.result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function createPrinter(name, deviceURI, ppd, options) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
creatingPrinter = true;
|
||||
const params = {
|
||||
"name": name,
|
||||
"deviceURI": deviceURI,
|
||||
"ppd": ppd
|
||||
};
|
||||
if (options) {
|
||||
if (options.shared !== undefined)
|
||||
params.shared = options.shared;
|
||||
if (options.location)
|
||||
params.location = options.location;
|
||||
if (options.information)
|
||||
params.information = options.information;
|
||||
if (options.errorPolicy)
|
||||
params.errorPolicy = options.errorPolicy;
|
||||
}
|
||||
|
||||
DMSService.sendRequest("cups.createPrinter", params, response => {
|
||||
creatingPrinter = false;
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to create printer") + " - " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo(I18n.tr("Printer created successfully"));
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deletePrinter(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.deletePrinter", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to delete printer") + " - " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo(I18n.tr("Printer deleted"));
|
||||
if (selectedPrinter === printerName) {
|
||||
selectedPrinter = "";
|
||||
}
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function acceptJobs(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.acceptJobs", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to enable job acceptance") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function rejectJobs(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.rejectJobs", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to disable job acceptance") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setPrinterShared(printerName, shared) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName,
|
||||
"shared": shared
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.setPrinterShared", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to update sharing") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setPrinterLocation(printerName, location) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName,
|
||||
"location": location
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.setPrinterLocation", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to update location") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function setPrinterInfo(printerName, info) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName,
|
||||
"info": info
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.setPrinterInfo", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to update description") + " - " + response.error);
|
||||
} else {
|
||||
getState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function printTestPage(printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.printTestPage", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to print test page") + " - " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo(I18n.tr("Test page sent to printer"));
|
||||
fetchJobsForPrinter(printerName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function moveJob(jobID, destPrinter) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"jobID": jobID,
|
||||
"destPrinter": destPrinter
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.moveJob", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to move job") + " - " + response.error);
|
||||
} else {
|
||||
fetchAllJobs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function restartJob(jobID) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"jobID": jobID
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.restartJob", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to restart job") + " - " + response.error);
|
||||
} else {
|
||||
fetchAllJobs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function holdJob(jobID, holdUntil) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"jobID": jobID
|
||||
};
|
||||
if (holdUntil) {
|
||||
params.holdUntil = holdUntil;
|
||||
}
|
||||
|
||||
DMSService.sendRequest("cups.holdJob", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to hold job") + " - " + response.error);
|
||||
} else {
|
||||
fetchAllJobs();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function addPrinterToClass(className, printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"className": className,
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.addPrinterToClass", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to add printer to class") + " - " + response.error);
|
||||
} else {
|
||||
getClasses();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function removePrinterFromClass(className, printerName) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"className": className,
|
||||
"printerName": printerName
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.removePrinterFromClass", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to remove printer from class") + " - " + response.error);
|
||||
} else {
|
||||
getClasses();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteClass(className) {
|
||||
if (!cupsAvailable)
|
||||
return;
|
||||
const params = {
|
||||
"className": className
|
||||
};
|
||||
|
||||
DMSService.sendRequest("cups.deleteClass", params, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError(I18n.tr("Failed to delete class") + " - " + response.error);
|
||||
} else {
|
||||
getClasses();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getPrinterData(printerName) {
|
||||
if (!printers || !printers[printerName])
|
||||
return null;
|
||||
return printers[printerName];
|
||||
}
|
||||
|
||||
function getJobStateTranslation(state) {
|
||||
switch (state) {
|
||||
case "pending":
|
||||
return I18n.tr("Pending");
|
||||
case "pending-held":
|
||||
return I18n.tr("Held");
|
||||
case "processing":
|
||||
return I18n.tr("Processing");
|
||||
case "processing-stopped":
|
||||
return I18n.tr("Stopped");
|
||||
case "canceled":
|
||||
return I18n.tr("Canceled");
|
||||
case "aborted":
|
||||
return I18n.tr("Aborted");
|
||||
case "completed":
|
||||
return I18n.tr("Completed");
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
readonly property var states: ({
|
||||
"idle": I18n.tr("Idle"),
|
||||
"processing": I18n.tr("Processing"),
|
||||
"stopped": I18n.tr("Stopped")
|
||||
})
|
||||
"idle": I18n.tr("Idle"),
|
||||
"processing": I18n.tr("Processing"),
|
||||
"stopped": I18n.tr("Stopped")
|
||||
})
|
||||
|
||||
readonly property var reasonsGeneral: ({
|
||||
"none": I18n.tr("None"),
|
||||
"other": I18n.tr("Other")
|
||||
})
|
||||
"none": I18n.tr("None"),
|
||||
"other": I18n.tr("Other")
|
||||
})
|
||||
|
||||
readonly property var reasonsSupplies: ({
|
||||
"toner-low": I18n.tr("Toner Low"),
|
||||
"toner-empty": I18n.tr("Toner Empty"),
|
||||
"marker-supply-low": I18n.tr("Marker Supply Low"),
|
||||
"marker-supply-empty": I18n.tr("Marker Supply Empty"),
|
||||
"marker-waste-almost-full": I18n.tr("Marker Waste Almost Full"),
|
||||
"marker-waste-full": I18n.tr("Marker Waste Full")
|
||||
})
|
||||
"toner-low": I18n.tr("Toner Low"),
|
||||
"toner-empty": I18n.tr("Toner Empty"),
|
||||
"marker-supply-low": I18n.tr("Marker Supply Low"),
|
||||
"marker-supply-empty": I18n.tr("Marker Supply Empty"),
|
||||
"marker-waste-almost-full": I18n.tr("Marker Waste Almost Full"),
|
||||
"marker-waste-full": I18n.tr("Marker Waste Full")
|
||||
})
|
||||
|
||||
readonly property var reasonsMedia: ({
|
||||
"media-low": I18n.tr("Media Low"),
|
||||
"media-empty": I18n.tr("Media Empty"),
|
||||
"media-needed": I18n.tr("Media Needed"),
|
||||
"media-jam": I18n.tr("Media Jam")
|
||||
})
|
||||
"media-low": I18n.tr("Media Low"),
|
||||
"media-empty": I18n.tr("Media Empty"),
|
||||
"media-needed": I18n.tr("Media Needed"),
|
||||
"media-jam": I18n.tr("Media Jam")
|
||||
})
|
||||
|
||||
readonly property var reasonsParts: ({
|
||||
"cover-open": I18n.tr("Cover Open"),
|
||||
"door-open": I18n.tr("Door Open"),
|
||||
"interlock-open": I18n.tr("Interlock Open"),
|
||||
"output-tray-missing": I18n.tr("Output Tray Missing"),
|
||||
"output-area-almost-full": I18n.tr("Output Area Almost Full"),
|
||||
"output-area-full": I18n.tr("Output Area Full")
|
||||
})
|
||||
"cover-open": I18n.tr("Cover Open"),
|
||||
"door-open": I18n.tr("Door Open"),
|
||||
"interlock-open": I18n.tr("Interlock Open"),
|
||||
"output-tray-missing": I18n.tr("Output Tray Missing"),
|
||||
"output-area-almost-full": I18n.tr("Output Area Almost Full"),
|
||||
"output-area-full": I18n.tr("Output Area Full")
|
||||
})
|
||||
|
||||
readonly property var reasonsErrors: ({
|
||||
"paused": I18n.tr("Paused"),
|
||||
"shutdown": I18n.tr("Shutdown"),
|
||||
"connecting-to-device": I18n.tr("Connecting to Device"),
|
||||
"timed-out": I18n.tr("Timed Out"),
|
||||
"stopping": I18n.tr("Stopping"),
|
||||
"stopped-partly": I18n.tr("Stopped Partly")
|
||||
})
|
||||
"paused": I18n.tr("Paused"),
|
||||
"shutdown": I18n.tr("Shutdown"),
|
||||
"connecting-to-device": I18n.tr("Connecting to Device"),
|
||||
"timed-out": I18n.tr("Timed Out"),
|
||||
"stopping": I18n.tr("Stopping"),
|
||||
"stopped-partly": I18n.tr("Stopped Partly")
|
||||
})
|
||||
|
||||
readonly property var reasonsService: ({
|
||||
"spool-area-full": I18n.tr("Spool Area Full"),
|
||||
"cups-missing-filter-warning": I18n.tr("CUPS Missing Filter Warning"),
|
||||
"cups-insecure-filter-warning": I18n.tr("CUPS Insecure Filter Warning")
|
||||
})
|
||||
"spool-area-full": I18n.tr("Spool Area Full"),
|
||||
"cups-missing-filter-warning": I18n.tr("CUPS Missing Filter Warning"),
|
||||
"cups-insecure-filter-warning": I18n.tr("CUPS Insecure Filter Warning")
|
||||
})
|
||||
|
||||
readonly property var reasonsConnectivity: ({
|
||||
"offline-report": I18n.tr("Offline Report"),
|
||||
"moving-to-paused": I18n.tr("Moving to Paused")
|
||||
})
|
||||
"offline-report": I18n.tr("Offline Report"),
|
||||
"moving-to-paused": I18n.tr("Moving to Paused")
|
||||
})
|
||||
|
||||
readonly property var severitySuffixes: ({
|
||||
"-error": I18n.tr("Error"),
|
||||
"-warning": I18n.tr("Warning"),
|
||||
"-report": I18n.tr("Report")
|
||||
})
|
||||
"-error": I18n.tr("Error"),
|
||||
"-warning": I18n.tr("Warning"),
|
||||
"-report": I18n.tr("Report")
|
||||
})
|
||||
|
||||
function getPrinterStateTranslation(state) {
|
||||
return states[state] || state
|
||||
return states[state] || state;
|
||||
}
|
||||
|
||||
function getPrinterStateReasonTranslation(reason) {
|
||||
let allReasons = Object.assign({}, reasonsGeneral, reasonsSupplies, reasonsMedia, reasonsParts, reasonsErrors, reasonsService, reasonsConnectivity)
|
||||
let allReasons = Object.assign({}, reasonsGeneral, reasonsSupplies, reasonsMedia, reasonsParts, reasonsErrors, reasonsService, reasonsConnectivity);
|
||||
|
||||
let basReason = reason
|
||||
let suffix = ""
|
||||
let basReason = reason;
|
||||
let suffix = "";
|
||||
|
||||
for (let s in severitySuffixes) {
|
||||
if (reason.endsWith(s)) {
|
||||
basReason = reason.slice(0, -s.length)
|
||||
suffix = severitySuffixes[s]
|
||||
break
|
||||
basReason = reason.slice(0, -s.length);
|
||||
suffix = severitySuffixes[s];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let translation = allReasons[basReason] || basReason
|
||||
return suffix ? translation + " (" + suffix + ")" : translation
|
||||
let translation = allReasons[basReason] || basReason;
|
||||
return suffix ? translation + " (" + suffix + ")" : translation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
@@ -14,6 +12,7 @@ Singleton {
|
||||
property bool dmsAvailable: false
|
||||
property var capabilities: []
|
||||
property int apiVersion: 0
|
||||
property string cliVersion: ""
|
||||
readonly property int expectedApiVersion: 1
|
||||
property var availablePlugins: []
|
||||
property var installedPlugins: []
|
||||
@@ -57,18 +56,18 @@ Singleton {
|
||||
|
||||
Component.onCompleted: {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
detectUpdateCommand()
|
||||
detectUpdateCommand();
|
||||
}
|
||||
}
|
||||
|
||||
function detectUpdateCommand() {
|
||||
checkingUpdateCommand = true
|
||||
checkAurHelper.running = true
|
||||
checkingUpdateCommand = true;
|
||||
checkAurHelper.running = true;
|
||||
}
|
||||
|
||||
function startSocketConnection() {
|
||||
if (socketPath && socketPath.length > 0) {
|
||||
testProcess.running = true
|
||||
testProcess.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,26 +78,26 @@ Singleton {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const helper = text.trim()
|
||||
const helper = text.trim();
|
||||
if (helper.includes("paru")) {
|
||||
checkDmsPackage.helper = "paru"
|
||||
checkDmsPackage.running = true
|
||||
checkDmsPackage.helper = "paru";
|
||||
checkDmsPackage.running = true;
|
||||
} else if (helper.includes("yay")) {
|
||||
checkDmsPackage.helper = "yay"
|
||||
checkDmsPackage.running = true
|
||||
checkDmsPackage.helper = "yay";
|
||||
checkDmsPackage.running = true;
|
||||
} else {
|
||||
updateCommand = "dms update"
|
||||
checkingUpdateCommand = false
|
||||
startSocketConnection()
|
||||
updateCommand = "dms update";
|
||||
checkingUpdateCommand = false;
|
||||
startSocketConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
updateCommand = "dms update"
|
||||
checkingUpdateCommand = false
|
||||
startSocketConnection()
|
||||
updateCommand = "dms update";
|
||||
checkingUpdateCommand = false;
|
||||
startSocketConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,22 +111,22 @@ Singleton {
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
if (text.includes("dms-shell-git")) {
|
||||
updateCommand = checkDmsPackage.helper + " -S dms-shell-git"
|
||||
updateCommand = checkDmsPackage.helper + " -S dms-shell-git";
|
||||
} else if (text.includes("dms-shell-bin")) {
|
||||
updateCommand = checkDmsPackage.helper + " -S dms-shell-bin"
|
||||
updateCommand = checkDmsPackage.helper + " -S dms-shell-bin";
|
||||
} else {
|
||||
updateCommand = "dms update"
|
||||
updateCommand = "dms update";
|
||||
}
|
||||
checkingUpdateCommand = false
|
||||
startSocketConnection()
|
||||
checkingUpdateCommand = false;
|
||||
startSocketConnection();
|
||||
}
|
||||
}
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode !== 0) {
|
||||
updateCommand = "dms update"
|
||||
checkingUpdateCommand = false
|
||||
startSocketConnection()
|
||||
updateCommand = "dms update";
|
||||
checkingUpdateCommand = false;
|
||||
startSocketConnection();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,21 +137,21 @@ Singleton {
|
||||
|
||||
onExited: exitCode => {
|
||||
if (exitCode === 0) {
|
||||
root.dmsAvailable = true
|
||||
connectSocket()
|
||||
root.dmsAvailable = true;
|
||||
connectSocket();
|
||||
} else {
|
||||
root.dmsAvailable = false
|
||||
root.dmsAvailable = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function connectSocket() {
|
||||
if (!dmsAvailable || isConnected || isConnecting) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
isConnecting = true
|
||||
requestSocket.connected = true
|
||||
isConnecting = true;
|
||||
requestSocket.connected = true;
|
||||
}
|
||||
|
||||
DankSocket {
|
||||
@@ -162,32 +161,32 @@ Singleton {
|
||||
|
||||
onConnectionStateChanged: {
|
||||
if (connected) {
|
||||
root.isConnected = true
|
||||
root.isConnecting = false
|
||||
root.connectionStateChanged()
|
||||
subscribeSocket.connected = true
|
||||
root.isConnected = true;
|
||||
root.isConnecting = false;
|
||||
root.connectionStateChanged();
|
||||
subscribeSocket.connected = true;
|
||||
} else {
|
||||
root.isConnected = false
|
||||
root.isConnecting = false
|
||||
root.apiVersion = 0
|
||||
root.capabilities = []
|
||||
root.connectionStateChanged()
|
||||
root.isConnected = false;
|
||||
root.isConnecting = false;
|
||||
root.apiVersion = 0;
|
||||
root.capabilities = [];
|
||||
root.connectionStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
parser: SplitParser {
|
||||
onRead: line => {
|
||||
if (!line || line.length === 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("DMSService: Request socket <<", line)
|
||||
console.log("DMSService: Request socket <<", line);
|
||||
|
||||
try {
|
||||
const response = JSON.parse(line)
|
||||
handleResponse(response)
|
||||
const response = JSON.parse(line);
|
||||
handleResponse(response);
|
||||
} catch (e) {
|
||||
console.warn("DMSService: Failed to parse request response:", line, e)
|
||||
console.warn("DMSService: Failed to parse request response:", line, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,25 +198,25 @@ Singleton {
|
||||
connected: false
|
||||
|
||||
onConnectionStateChanged: {
|
||||
root.subscribeConnected = connected
|
||||
root.subscribeConnected = connected;
|
||||
if (connected) {
|
||||
sendSubscribeRequest()
|
||||
sendSubscribeRequest();
|
||||
}
|
||||
}
|
||||
|
||||
parser: SplitParser {
|
||||
onRead: line => {
|
||||
if (!line || line.length === 0) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("DMSService: Subscribe socket <<", line)
|
||||
console.log("DMSService: Subscribe socket <<", line);
|
||||
|
||||
try {
|
||||
const response = JSON.parse(line)
|
||||
handleSubscriptionEvent(response)
|
||||
const response = JSON.parse(line);
|
||||
handleSubscriptionEvent(response);
|
||||
} catch (e) {
|
||||
console.warn("DMSService: Failed to parse subscription event:", line, e)
|
||||
console.warn("DMSService: Failed to parse subscription event:", line, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,319 +225,317 @@ Singleton {
|
||||
function sendSubscribeRequest() {
|
||||
const request = {
|
||||
"method": "subscribe"
|
||||
}
|
||||
};
|
||||
|
||||
if (activeSubscriptions.length > 0) {
|
||||
request.params = {
|
||||
"services": activeSubscriptions
|
||||
}
|
||||
console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions))
|
||||
};
|
||||
console.log("DMSService: Subscribing to services:", JSON.stringify(activeSubscriptions));
|
||||
} else {
|
||||
console.log("DMSService: Subscribing to all services")
|
||||
console.log("DMSService: Subscribing to all services");
|
||||
}
|
||||
|
||||
subscribeSocket.send(request)
|
||||
subscribeSocket.send(request);
|
||||
}
|
||||
|
||||
function subscribe(services) {
|
||||
if (!Array.isArray(services)) {
|
||||
services = [services]
|
||||
services = [services];
|
||||
}
|
||||
|
||||
activeSubscriptions = services
|
||||
activeSubscriptions = services;
|
||||
|
||||
if (subscribeConnected) {
|
||||
subscribeSocket.connected = false
|
||||
subscribeSocket.connected = false;
|
||||
Qt.callLater(() => {
|
||||
subscribeSocket.connected = true
|
||||
})
|
||||
subscribeSocket.connected = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function addSubscription(service) {
|
||||
if (activeSubscriptions.includes("all")) {
|
||||
console.warn("DMSService: Cannot add specific subscription when subscribed to 'all'")
|
||||
return
|
||||
}
|
||||
|
||||
if (activeSubscriptions.includes("all"))
|
||||
return;
|
||||
if (!activeSubscriptions.includes(service)) {
|
||||
const newSubs = [...activeSubscriptions, service]
|
||||
subscribe(newSubs)
|
||||
const newSubs = [...activeSubscriptions, service];
|
||||
subscribe(newSubs);
|
||||
}
|
||||
}
|
||||
|
||||
function removeSubscription(service) {
|
||||
if (activeSubscriptions.includes("all")) {
|
||||
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace"]
|
||||
const filtered = allServices.filter(s => s !== service)
|
||||
subscribe(filtered)
|
||||
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "dwl", "brightness", "extworkspace"];
|
||||
const filtered = allServices.filter(s => s !== service);
|
||||
subscribe(filtered);
|
||||
} else {
|
||||
const filtered = activeSubscriptions.filter(s => s !== service)
|
||||
const filtered = activeSubscriptions.filter(s => s !== service);
|
||||
if (filtered.length === 0) {
|
||||
console.warn("DMSService: Cannot remove last subscription")
|
||||
return
|
||||
console.warn("DMSService: Cannot remove last subscription");
|
||||
return;
|
||||
}
|
||||
subscribe(filtered)
|
||||
subscribe(filtered);
|
||||
}
|
||||
}
|
||||
|
||||
function subscribeAll() {
|
||||
subscribe(["all"])
|
||||
subscribe(["all"]);
|
||||
}
|
||||
|
||||
function subscribeAllExcept(excludeServices) {
|
||||
if (!Array.isArray(excludeServices)) {
|
||||
excludeServices = [excludeServices]
|
||||
excludeServices = [excludeServices];
|
||||
}
|
||||
|
||||
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "cups", "dwl", "brightness", "extworkspace"]
|
||||
const filtered = allServices.filter(s => !excludeServices.includes(s))
|
||||
subscribe(filtered)
|
||||
const allServices = ["network", "loginctl", "freedesktop", "gamma", "bluetooth", "cups", "dwl", "brightness", "extworkspace"];
|
||||
const filtered = allServices.filter(s => !excludeServices.includes(s));
|
||||
subscribe(filtered);
|
||||
}
|
||||
|
||||
function handleSubscriptionEvent(response) {
|
||||
if (response.error) {
|
||||
if (response.error.includes("unknown method") && response.error.includes("subscribe")) {
|
||||
if (!shownOutdatedError) {
|
||||
console.error("DMSService: Server does not support subscribe method")
|
||||
ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand)
|
||||
shownOutdatedError = true
|
||||
console.error("DMSService: Server does not support subscribe method");
|
||||
ToastService.showError(I18n.tr("DMS out of date"), I18n.tr("To update, run the following command:"), updateCommand);
|
||||
shownOutdatedError = true;
|
||||
}
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.result) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
const service = response.result.service
|
||||
const data = response.result.data
|
||||
const service = response.result.service;
|
||||
const data = response.result.data;
|
||||
|
||||
if (service === "server") {
|
||||
apiVersion = data.apiVersion || 0
|
||||
capabilities = data.capabilities || []
|
||||
apiVersion = data.apiVersion || 0;
|
||||
cliVersion = data.cliVersion || "";
|
||||
capabilities = data.capabilities || [];
|
||||
|
||||
console.info("DMSService: Connected (API v" + apiVersion + ") -", JSON.stringify(capabilities))
|
||||
console.info("DMSService: Connected (API v" + apiVersion + ", CLI " + cliVersion + ") -", JSON.stringify(capabilities));
|
||||
|
||||
if (apiVersion < expectedApiVersion) {
|
||||
ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")")
|
||||
ToastService.showError("DMS server is outdated (API v" + apiVersion + ", expected v" + expectedApiVersion + ")");
|
||||
}
|
||||
|
||||
capabilitiesReceived()
|
||||
capabilitiesReceived();
|
||||
} else if (service === "network") {
|
||||
networkStateUpdate(data)
|
||||
networkStateUpdate(data);
|
||||
} else if (service === "network.credentials") {
|
||||
credentialsRequest(data)
|
||||
credentialsRequest(data);
|
||||
} else if (service === "loginctl") {
|
||||
if (data.event) {
|
||||
loginctlEvent(data)
|
||||
loginctlEvent(data);
|
||||
} else {
|
||||
loginctlStateUpdate(data)
|
||||
loginctlStateUpdate(data);
|
||||
}
|
||||
} else if (service === "bluetooth.pairing") {
|
||||
bluetoothPairingRequest(data)
|
||||
bluetoothPairingRequest(data);
|
||||
} else if (service === "cups") {
|
||||
cupsStateUpdate(data)
|
||||
cupsStateUpdate(data);
|
||||
} else if (service === "dwl") {
|
||||
dwlStateUpdate(data)
|
||||
dwlStateUpdate(data);
|
||||
} else if (service === "brightness") {
|
||||
brightnessStateUpdate(data)
|
||||
brightnessStateUpdate(data);
|
||||
} else if (service === "brightness.update") {
|
||||
if (data.device) {
|
||||
brightnessDeviceUpdate(data.device)
|
||||
brightnessDeviceUpdate(data.device);
|
||||
}
|
||||
} else if (service === "extworkspace") {
|
||||
extWorkspaceStateUpdate(data)
|
||||
extWorkspaceStateUpdate(data);
|
||||
} else if (service === "wlroutput") {
|
||||
wlrOutputStateUpdate(data)
|
||||
wlrOutputStateUpdate(data);
|
||||
} else if (service === "evdev") {
|
||||
if (data.capsLock !== undefined) {
|
||||
capsLockState = data.capsLock
|
||||
capsLockState = data.capsLock;
|
||||
}
|
||||
evdevStateUpdate(data)
|
||||
evdevStateUpdate(data);
|
||||
}
|
||||
}
|
||||
|
||||
function sendRequest(method, params, callback) {
|
||||
if (!isConnected) {
|
||||
console.warn("DMSService.sendRequest: Not connected, method:", method)
|
||||
console.warn("DMSService.sendRequest: Not connected, method:", method);
|
||||
if (callback) {
|
||||
callback({
|
||||
"error": "not connected to DMS socket"
|
||||
})
|
||||
"error": "not connected to DMS socket"
|
||||
});
|
||||
}
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
requestIdCounter++
|
||||
const id = Date.now() + requestIdCounter
|
||||
requestIdCounter++;
|
||||
const id = Date.now() + requestIdCounter;
|
||||
const request = {
|
||||
"id": id,
|
||||
"method": method
|
||||
}
|
||||
};
|
||||
|
||||
if (params) {
|
||||
request.params = params
|
||||
request.params = params;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
pendingRequests[id] = callback
|
||||
pendingRequests[id] = callback;
|
||||
}
|
||||
|
||||
console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method)
|
||||
requestSocket.send(request)
|
||||
console.log("DMSService.sendRequest: Sending request id=" + id + " method=" + method);
|
||||
requestSocket.send(request);
|
||||
}
|
||||
|
||||
function handleResponse(response) {
|
||||
const callback = pendingRequests[response.id]
|
||||
const callback = pendingRequests[response.id];
|
||||
|
||||
if (callback) {
|
||||
delete pendingRequests[response.id]
|
||||
callback(response)
|
||||
delete pendingRequests[response.id];
|
||||
callback(response);
|
||||
}
|
||||
}
|
||||
|
||||
function ping(callback) {
|
||||
sendRequest("ping", null, callback)
|
||||
sendRequest("ping", null, callback);
|
||||
}
|
||||
|
||||
function listPlugins(callback) {
|
||||
sendRequest("plugins.list", null, response => {
|
||||
if (response.result) {
|
||||
availablePlugins = response.result
|
||||
pluginsListReceived(response.result)
|
||||
}
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
})
|
||||
if (response.result) {
|
||||
availablePlugins = response.result;
|
||||
pluginsListReceived(response.result);
|
||||
}
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function listInstalled(callback) {
|
||||
sendRequest("plugins.listInstalled", null, response => {
|
||||
if (response.result) {
|
||||
installedPlugins = response.result
|
||||
installedPluginsReceived(response.result)
|
||||
}
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
})
|
||||
if (response.result) {
|
||||
installedPlugins = response.result;
|
||||
installedPluginsReceived(response.result);
|
||||
}
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function search(query, category, compositor, capability, callback) {
|
||||
const params = {
|
||||
"query": query
|
||||
}
|
||||
};
|
||||
if (category) {
|
||||
params.category = category
|
||||
params.category = category;
|
||||
}
|
||||
if (compositor) {
|
||||
params.compositor = compositor
|
||||
params.compositor = compositor;
|
||||
}
|
||||
if (capability) {
|
||||
params.capability = capability
|
||||
params.capability = capability;
|
||||
}
|
||||
|
||||
sendRequest("plugins.search", params, response => {
|
||||
if (response.result) {
|
||||
searchResultsReceived(response.result)
|
||||
}
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
})
|
||||
if (response.result) {
|
||||
searchResultsReceived(response.result);
|
||||
}
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function install(pluginName, callback) {
|
||||
sendRequest("plugins.install", {
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled()
|
||||
}
|
||||
})
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uninstall(pluginName, callback) {
|
||||
sendRequest("plugins.uninstall", {
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled()
|
||||
}
|
||||
})
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function update(pluginName, callback) {
|
||||
sendRequest("plugins.update", {
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response)
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled()
|
||||
}
|
||||
})
|
||||
"name": pluginName
|
||||
}, response => {
|
||||
if (callback) {
|
||||
callback(response);
|
||||
}
|
||||
if (!response.error) {
|
||||
listInstalled();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function lockSession(callback) {
|
||||
sendRequest("loginctl.lock", null, callback)
|
||||
sendRequest("loginctl.lock", null, callback);
|
||||
}
|
||||
|
||||
function unlockSession(callback) {
|
||||
sendRequest("loginctl.unlock", null, callback)
|
||||
sendRequest("loginctl.unlock", null, callback);
|
||||
}
|
||||
|
||||
function bluetoothPair(devicePath, callback) {
|
||||
sendRequest("bluetooth.pair", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
"device": devicePath
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothConnect(devicePath, callback) {
|
||||
sendRequest("bluetooth.connect", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
"device": devicePath
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothDisconnect(devicePath, callback) {
|
||||
sendRequest("bluetooth.disconnect", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
"device": devicePath
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothRemove(devicePath, callback) {
|
||||
sendRequest("bluetooth.remove", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
"device": devicePath
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothTrust(devicePath, callback) {
|
||||
sendRequest("bluetooth.trust", {
|
||||
"device": devicePath
|
||||
}, callback)
|
||||
"device": devicePath
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothSubmitPairing(token, secrets, accept, callback) {
|
||||
sendRequest("bluetooth.pairing.submit", {
|
||||
"token": token,
|
||||
"secrets": secrets,
|
||||
"accept": accept
|
||||
}, callback)
|
||||
"token": token,
|
||||
"secrets": secrets,
|
||||
"accept": accept
|
||||
}, callback);
|
||||
}
|
||||
|
||||
function bluetoothCancelPairing(token, callback) {
|
||||
sendRequest("bluetooth.pairing.cancel", {
|
||||
"token": token
|
||||
}, callback)
|
||||
"token": token
|
||||
}, callback);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user